mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1252 lines
33 KiB
1252 lines
33 KiB
/*
|
|
This file was derived from the libwww code, version 2.15, from CERN.
|
|
A number of modifications have been made by Spyglass.
|
|
|
|
Copyright 1995 Spyglass, Inc.
|
|
All Rights Reserved
|
|
|
|
[email protected]
|
|
*/
|
|
|
|
|
|
/*****************************************************************************
|
|
Included Files
|
|
*****************************************************************************/
|
|
#include "all.h"
|
|
|
|
|
|
/*****************************************************************************
|
|
Constants and Structures
|
|
*****************************************************************************/
|
|
#define PUTS(s) (*target->isa->put_string)(target, s)
|
|
#define START(e) (*target->isa->start_element)(target, e, 0, 0)
|
|
#define END(e) (*target->isa->end_element)(target, e)
|
|
|
|
struct _HTStructured
|
|
{
|
|
CONST HTStructuredClass *isa;
|
|
/* ... */
|
|
};
|
|
|
|
struct _HTStream
|
|
{
|
|
CONST HTStreamClass *isa;
|
|
/* ... */
|
|
};
|
|
|
|
/*****************************************************************************
|
|
More Constants
|
|
*****************************************************************************/
|
|
#define STATE_FILE_STREAMINIT (STATE_OTHER + 1)
|
|
#define STATE_FILE_COPYING (STATE_OTHER + 2)
|
|
|
|
#ifdef FEATURE_LOCAL_DIRECTORY
|
|
int HTLoadDir (struct Mwin *tw, HTRequest *request, char *pszLocalname);
|
|
#endif
|
|
|
|
/*****************************************************************************
|
|
Private prototypes
|
|
*****************************************************************************/
|
|
#ifdef MAC
|
|
extern struct Viewer_Info *
|
|
PREF_GetViewerInfoBy_FileType
|
|
(OSType reqType);
|
|
#endif
|
|
|
|
static int
|
|
HTLoadFile_TryFTP
|
|
(struct Mwin *tw,
|
|
struct Data_LoadFile* pData,
|
|
char *addr);
|
|
|
|
int
|
|
HTLoadFile_Async_SetFileInfo
|
|
(struct Mwin* tw,
|
|
struct Data_LoadFile* pData,
|
|
char* pszURL,
|
|
char** pszLocalname);
|
|
|
|
int
|
|
HTLoadFile_Async_Init
|
|
(struct Mwin *tw,
|
|
void **ppInfo,
|
|
int openType);
|
|
|
|
int
|
|
HTLoadFile_Async_File_Copy
|
|
(struct Mwin *tw,
|
|
struct Data_LoadFile *pData);
|
|
|
|
int
|
|
HTLoadFile_Async_File_StreamInit
|
|
(struct Mwin *tw,
|
|
struct Data_LoadFile *pData);
|
|
|
|
int
|
|
HTLoadFile_Async_Abort
|
|
(struct Mwin *tw,
|
|
struct Data_LoadFile *pData);
|
|
|
|
|
|
/*****************************************************************************
|
|
Code
|
|
*****************************************************************************/
|
|
/*****************************************************************************
|
|
HTFileFormat
|
|
*****************************************************************************/
|
|
PUBLIC HTFormat HTFileFormat(CONST char *filename, HTAtom *pencoding, HTAtom *planguage)
|
|
{
|
|
char *p;
|
|
CONST char *pslash;
|
|
|
|
if (planguage)
|
|
{
|
|
*planguage = 0; /* note that this isn't supported at all yet */
|
|
}
|
|
|
|
pslash = strrchr(filename, '/');
|
|
if (pslash)
|
|
{
|
|
pslash++;
|
|
/* the filename passed in was a URL. pslash now points to the basename */
|
|
}
|
|
else
|
|
{
|
|
pslash = filename;
|
|
}
|
|
|
|
p = strrchr(pslash, '.');
|
|
/* In the case of an HTTP/0.9 server, we have to assume that the root page
|
|
(e.g. "http://www.foo.com/") is HTML even though it doesn't have a
|
|
filename, let alone an extension. */
|
|
|
|
#ifndef _GIBRALTAR
|
|
//
|
|
// Without any extention at all, we assume html
|
|
//
|
|
if (p || *pslash == '\0')
|
|
#endif // _GIBRALTAR
|
|
{
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ((q - szSuff) < 32) below causes the NULL char
|
|
// to be written one past the boundary!!!!
|
|
//
|
|
//char szSuff[32];
|
|
char szSuff[SUFF_BUF_LEN + 1];
|
|
char *q;
|
|
struct Viewer_Info *pvi = NULL;
|
|
|
|
if (p)
|
|
{
|
|
szSuff[0] = 0;
|
|
|
|
p++; /* skip the dot */
|
|
q = szSuff;
|
|
while (*p && (*p != '/') && ((q - szSuff) < SUFF_BUF_LEN))
|
|
{
|
|
*q++ = *p++;
|
|
}
|
|
*q = 0;
|
|
|
|
XX_DMsg(DBG_WWW, ("HTFileFormat: Looking for extension %s... ", szSuff));
|
|
pvi = PREF_GetViewerInfoBy_Suffix(szSuff);
|
|
}
|
|
else
|
|
{
|
|
pvi = PREF_GetViewerInfoBy_Suffix("html");
|
|
}
|
|
|
|
if (pvi)
|
|
{
|
|
XX_DMsg(DBG_WWW, ("found! MIME=%s\n", HTAtom_name(pvi->atomMIMEType)));
|
|
if (pencoding)
|
|
*pencoding = pvi->atomEncoding;
|
|
return pvi->atomMIMEType;
|
|
}
|
|
XX_DMsg(DBG_WWW, ("Suffix not found.\n"));
|
|
if (pencoding)
|
|
*pencoding = 0;
|
|
return WWW_BINARY;
|
|
}
|
|
#ifndef _GIBRALTAR
|
|
else
|
|
{
|
|
if (pencoding)
|
|
*pencoding = HTAtom_for("8bit");
|
|
|
|
return WWW_PLAINTEXT;
|
|
}
|
|
#endif // _GIBRALTAR
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
HTContentToEncoding
|
|
*****************************************************************************/
|
|
PUBLIC HTAtom HTContentToEncoding(HTAtom content_type)
|
|
{
|
|
struct Viewer_Info *pvi;
|
|
|
|
pvi = PREF_GetViewerInfoBy_MIMEAtom(content_type);
|
|
if (pvi)
|
|
{
|
|
return pvi->atomEncoding;
|
|
}
|
|
else
|
|
{
|
|
return HTAtom_for("binary");
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
HTFileSuffix
|
|
*****************************************************************************/
|
|
PUBLIC CONST char *HTFileSuffix(HTAtom rep)
|
|
{
|
|
struct Viewer_Info *pvi;
|
|
static char szSuff[SUFF_BUF_LEN + 1];
|
|
int i;
|
|
char *p;
|
|
|
|
pvi = PREF_GetViewerInfoBy_MIMEAtom(rep);
|
|
if (pvi && pvi->nSuffixes)
|
|
{
|
|
for (i=0; i<pvi->nSuffixes; i++)
|
|
{
|
|
PREF_GetSuffix(szSuff, pvi, i);
|
|
p = szSuff;
|
|
if (*p == '.')
|
|
{
|
|
p++;
|
|
}
|
|
#ifdef UNIX
|
|
if (strlen(p) >= 4) /* we prefer our suffixes long */
|
|
#else
|
|
if (strlen(p) <= 3)
|
|
#endif
|
|
{
|
|
return szSuff;
|
|
}
|
|
}
|
|
/*
|
|
A suffix could not be found. Just return the first one
|
|
*/
|
|
if (0 > PREF_GetSuffix(szSuff, pvi, 0))
|
|
return NULL;
|
|
return szSuff;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
HTLocalName
|
|
*****************************************************************************/
|
|
/* Convert filenames between local and WWW formats
|
|
** -----------------------------------------------
|
|
** Make up a suitable name for saving the node in
|
|
**
|
|
** E.g. $(HOME)/WWW/news/[email protected]
|
|
** $(HOME)/WWW/http/crnvmc/FIND/xx.xxx.xx
|
|
**
|
|
** On exit,
|
|
** returns a GTR_MALLOC'ed string which must be freed by the caller.
|
|
*/
|
|
PUBLIC char *HTLocalName(CONST char *name)
|
|
{
|
|
char *host = HTParse(name, "", PARSE_HOST);
|
|
int iLoc;
|
|
#ifdef WIN32
|
|
int iSlash;
|
|
#endif
|
|
|
|
if (!host || !*host || (0 == strcasecomp(host, HTHostName())) ||
|
|
(0 == strcasecomp(host, "localhost")))
|
|
{
|
|
char *path;
|
|
|
|
if (host)
|
|
{
|
|
GTR_FREE(host);
|
|
}
|
|
path = HTParse(name, "", PARSE_PATH + PARSE_PUNCTUATION);
|
|
|
|
#ifdef MAC
|
|
#define SLASH ':'
|
|
/* Convert slashes to colons before we unescape */
|
|
for (iLoc = 0; path[iLoc]; iLoc++)
|
|
{
|
|
if (path[iLoc] == '/')
|
|
path[iLoc] = SLASH;
|
|
}
|
|
#endif
|
|
|
|
HTUnEscape (path); /* Interpret % signs */
|
|
|
|
/*
|
|
BEGIN NCSA Copy-Paste
|
|
*/
|
|
|
|
#ifdef WIN32
|
|
#define SLASH '\\'
|
|
if ( (path[0] == '/') && (strchr(path, ':') || strchr(path, '|')) )
|
|
{
|
|
char *shuffle = path; // We have drive spec - strip leading slash
|
|
|
|
while (*shuffle && (*(shuffle + 1)))
|
|
{
|
|
*shuffle = *(shuffle + 1);
|
|
shuffle++;
|
|
}
|
|
*shuffle = 0;
|
|
}
|
|
iSlash = 0;
|
|
for (iLoc = 0; iLoc < strlen(path); iLoc++)
|
|
{
|
|
if (path[iLoc] == '|')
|
|
path[iLoc] = ':';
|
|
|
|
else if (path[iLoc] == '/')
|
|
{
|
|
path[iLoc] = SLASH;
|
|
iSlash++;
|
|
}
|
|
else if (path[iLoc] == SLASH)
|
|
iSlash++;
|
|
}
|
|
if ((path[strlen(path) - 1] == SLASH) && (iSlash > 1))
|
|
path[strlen(path) - 1] = 0;
|
|
#endif
|
|
|
|
#ifdef MAC
|
|
/*
|
|
Remove initial colon. Note that this could cause a problem with a
|
|
relative path name, if a person were so foolish as to enter one.
|
|
*/
|
|
if (path[0] == ':')
|
|
memmove(path, path + 1, strlen(path));
|
|
#endif
|
|
/*
|
|
END NCSA Copy-Paste
|
|
*/
|
|
|
|
XX_DMsg(DBG_WWW, ("Node `%s' means path `%s'\n", name, path));
|
|
return (path);
|
|
}
|
|
else
|
|
{
|
|
GTR_FREE(host);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Adjust local file name -- if it's relative to the document
|
|
// it's embedded in (and that doc is a 'file:' itself),
|
|
// adjust it to be an absolute reference
|
|
//
|
|
// Note: this may return a newly allocate a new string and free the old one
|
|
// so the input string must have been malloc'ed
|
|
//
|
|
static char *AdjustLocalNameIfRelative( struct Mwin *tw, char *localname )
|
|
{
|
|
char *retval = localname;
|
|
|
|
if ( tw && tw->w3doc && tw->w3doc->szActualURL )
|
|
{
|
|
char *p = tw->w3doc->szActualURL;
|
|
|
|
if ( _strnicmp( p, "file:", 5 ) == 0 )
|
|
{
|
|
char *s;
|
|
|
|
p += 5; // move past 'file:'
|
|
if ( s = strrchr( p, '\\' ) )
|
|
{
|
|
s++; // move past the last slash
|
|
if ( localname[0] && localname[0] != '\\' && localname[1] != ':' ) // is it relative?
|
|
{
|
|
char *newlocalname = (char *) GTR_MALLOC( (s-p) + strlen(localname) + 1);
|
|
|
|
if ( newlocalname )
|
|
{
|
|
//
|
|
// Build absolute local name
|
|
//
|
|
strncpy( newlocalname, p, (s-p) );
|
|
strcpy( newlocalname + (s-p), localname );
|
|
GTR_FREE( localname );
|
|
|
|
retval = newlocalname;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
HTDirEntry
|
|
|
|
Output one directory entry
|
|
*****************************************************************************/
|
|
PUBLIC void HTDirEntry(HTStructured * target, CONST char *tail, CONST char *entry, BOOL isdir)
|
|
{
|
|
char *relative;
|
|
char *escaped = HTEscape(entry, URL_XPALPHAS, '\0');
|
|
char buf[_MAX_PATH+5];
|
|
|
|
/* If empty tail, gives absolute ref below */
|
|
relative = (char *) GTR_MALLOC(strlen(tail) + strlen(escaped) + 2);
|
|
if (relative)
|
|
{
|
|
sprintf(relative, "%s/%s", tail, escaped);
|
|
HTStartAnchor(target, NULL, relative);
|
|
|
|
GTR_FREE(relative);
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(NULL, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
}
|
|
GTR_FREE(escaped);
|
|
if (isdir)
|
|
{
|
|
sprintf (buf, "< %s > ", entry);
|
|
PUTS(buf);
|
|
}
|
|
else
|
|
PUTS(entry);
|
|
END(HTML_A);
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
HTDirTitles
|
|
|
|
Output parent directory entry
|
|
|
|
This gives the TITLE and H1 header, and also a link
|
|
to the parent directory if appropriate.
|
|
*****************************************************************************/
|
|
PUBLIC void HTDirTitles(HTStructured * target, CONST char *szURL, BOOL bLocal)
|
|
|
|
{
|
|
char *path;
|
|
char *current;
|
|
|
|
if (bLocal)
|
|
path = GTR_strdup (szURL);
|
|
else
|
|
path = HTParse(szURL, "", PARSE_PATH + PARSE_PUNCTUATION);
|
|
|
|
current = strrchr(path, '/'); /* last part or "" */
|
|
|
|
if (current)
|
|
{
|
|
char *printable = NULL;
|
|
printable = GTR_strdup((current+1));
|
|
if (!bLocal)
|
|
HTUnEscape(printable);
|
|
START(HTML_TITLE);
|
|
if (*printable)
|
|
{
|
|
PUTS(printable);
|
|
//PUTS(" directory");
|
|
PUTS(GTR_GetString(SID_INF_DIRECTORY));
|
|
}
|
|
else
|
|
{
|
|
/* PUTS("Welcome"); */
|
|
//PUTS("Top Level Directory");
|
|
PUTS(GTR_GetString(SID_INF_TOP_LEVEL_DIRECTORY));
|
|
}
|
|
END(HTML_TITLE);
|
|
|
|
START(HTML_H1);
|
|
//PUTS(*printable ? printable : "Top Level");
|
|
PUTS(*printable ? printable : GTR_GetString(SID_INF_TOP_LEVEL));
|
|
END(HTML_H1);
|
|
GTR_FREE(printable);
|
|
}
|
|
|
|
/* Make link back to parent directory */
|
|
if (current && current[1])
|
|
{ /* was a slash AND something else too */
|
|
char *parent;
|
|
char *relative;
|
|
*current++ = 0;
|
|
parent = strrchr(path, '/'); /* penultimate slash */
|
|
|
|
relative = (char *) GTR_MALLOC(strlen(current) + 4);
|
|
if (relative)
|
|
{
|
|
sprintf(relative, "%s/..", current);
|
|
HTStartAnchor(target, "", relative);
|
|
GTR_FREE(relative);
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(NULL, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
}
|
|
|
|
//PUTS("Up to ");
|
|
PUTS(GTR_GetString(SID_INF_UP_TO));
|
|
if (parent)
|
|
{
|
|
char *printable = NULL;
|
|
printable = GTR_strdup((parent+1));
|
|
if (!bLocal)
|
|
HTUnEscape(printable);
|
|
PUTS(printable);
|
|
GTR_FREE(printable);
|
|
}
|
|
else
|
|
{
|
|
PUTS("/");
|
|
}
|
|
|
|
END(HTML_A);
|
|
|
|
}
|
|
if (path)
|
|
GTR_FREE(path);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
HTLoadFile_Async_SetFileInfo
|
|
*****************************************************************************/
|
|
int
|
|
HTLoadFile_Async_SetFileInfo
|
|
(struct Mwin* tw,
|
|
struct Data_LoadFile* pData,
|
|
char* pszURL,
|
|
char** pszLocalname)
|
|
{
|
|
char *pszFilename;
|
|
HTFormat format;
|
|
HTAtom encoding;
|
|
HTAtom language;
|
|
char *myhost = HTParse (pszURL, "", PARSE_HOST);
|
|
|
|
if (myhost)
|
|
{
|
|
if (*myhost)
|
|
{
|
|
GTR_FREE (myhost); /* be a good boy and clean up memory before we leave */
|
|
return HTLoadFile_TryFTP (tw, pData, pszURL);
|
|
}
|
|
GTR_FREE (myhost); /* memory cleanup */
|
|
}
|
|
|
|
/* Reduce the filename to a basic form (hopefully unique!) */
|
|
pszFilename = HTParse (pszURL, "", PARSE_PATH | PARSE_PUNCTUATION);
|
|
|
|
*pszLocalname = HTLocalName (pszURL);
|
|
if (!*pszLocalname)
|
|
{ /* No localname */
|
|
*pData->pStatus = -403;
|
|
ERR_ReportError (tw, SID_ERR_FILE_NOT_FOUND_S, pData->request->destination->szActualURL, NULL);
|
|
return STATE_DONE;
|
|
}
|
|
|
|
/* take care of the case where we have been given (via ShowFile event) the MIMEtype */
|
|
if (tw && tw->SDI_MimeType != 0)
|
|
{
|
|
struct Viewer_Info* pvi = NULL;
|
|
pvi = PREF_GetViewerInfoBy_MIMEAtom (tw->SDI_MimeType);
|
|
if (pvi)
|
|
{
|
|
format = pvi->atomMIMEType;
|
|
encoding = pvi->atomEncoding;
|
|
language = 0;
|
|
goto GotIt;
|
|
}
|
|
}
|
|
|
|
#ifdef MAC
|
|
{ /* see if we can figure out the type ourselves from the fileTYPE */
|
|
struct Viewer_Info* pvi = NULL;
|
|
Str255 spMacFilename;
|
|
FInfo fndrInfo;
|
|
|
|
strncpy (spMacFilename, *pszLocalname, sizeof (Str255));
|
|
c2pstr (spMacFilename);
|
|
|
|
if (GetFInfo (spMacFilename, 0, &fndrInfo) == noErr)
|
|
{
|
|
if (fndrInfo.fdType == 'TEXT')
|
|
{ /* TEXT is inconclusive, check based on extension */
|
|
format = HTFileFormat (pszFilename, &encoding, &language);
|
|
if (format == WWW_BINARY)
|
|
{
|
|
pvi = PREF_GetViewerInfoBy_MIMEAtom (WWW_PLAINTEXT);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pvi = PREF_GetViewerInfoBy_FileType (fndrInfo.fdType);
|
|
}
|
|
|
|
if (pvi)
|
|
{
|
|
format = pvi->atomMIMEType;
|
|
encoding = pvi->atomEncoding;
|
|
language = 0;
|
|
}
|
|
}
|
|
|
|
if (!pvi)
|
|
format = HTFileFormat (pszFilename, &encoding, &language);
|
|
}
|
|
#else
|
|
format = HTFileFormat (pszFilename, &encoding, &language);
|
|
#endif
|
|
|
|
GotIt:
|
|
/* memory cleanup */
|
|
if (pszFilename)
|
|
{
|
|
GTR_FREE (pszFilename);
|
|
pszFilename = NULL;
|
|
}
|
|
|
|
pData->request->content_type = format;
|
|
pData->request->content_encoding = encoding;
|
|
pData->request->content_language = language;
|
|
|
|
return STATE_INIT;
|
|
} /* HTLoadFile_Async_SetFileInfo */
|
|
|
|
|
|
/*****************************************************************************
|
|
HTLoadFile_Async_Init
|
|
|
|
NOTES:
|
|
Since we are reading a local file, we record that fact in the
|
|
request structure. If this request happens to end up in the
|
|
FileWriter class, that class can avoid writing a temp file
|
|
and simply read this file directly.
|
|
|
|
It is the responsibility of FileWriter to make sure that this
|
|
filename is not marked for deletion as a temporary file.
|
|
|
|
It is the responsibility of the caller (loaddoc.c) to make sure
|
|
that this string gets freed.
|
|
|
|
The "openType" parameter is used to determine if we are opening a local
|
|
file, or handling a "cache" file. This was done to condense the dcache
|
|
code with this code, since there was considerable overlap in functionality.
|
|
0 = open local
|
|
1 = dcache
|
|
other = undefined
|
|
[der: 5/24/95]
|
|
|
|
*****************************************************************************/
|
|
int
|
|
HTLoadFile_Async_Init
|
|
(struct Mwin *tw,
|
|
void **ppInfo,
|
|
int openType)
|
|
{
|
|
struct Params_InitStream* pis;
|
|
struct Params_LoadAsync* pParams;
|
|
struct Data_LoadFile* pData;
|
|
char *pszURL;
|
|
char *pszLocalname;
|
|
|
|
pParams = *ppInfo;
|
|
|
|
|
|
/****************************************/
|
|
|
|
/* this code copied from FTP_DoInit() to remove trailing slash */
|
|
/* this line fixed the infinite looping bug */
|
|
if (openType == 0) /* local file rather than dcache */
|
|
{
|
|
char *name;
|
|
|
|
name = pParams->request->destination->szActualURL;
|
|
|
|
if (!name || !*name)
|
|
{
|
|
*pParams->pStatus = HT_INTERNAL;
|
|
return STATE_DONE;
|
|
}
|
|
|
|
/* It's common for someone to enter an invalid directory URL which
|
|
ends in a slash ("ftp://foo.com/pub/mac/"), so make sure this
|
|
isn't malformed like that. */
|
|
{
|
|
char *filename;
|
|
char *p = NULL;
|
|
char buf[MAX_URL_STRING];
|
|
|
|
filename = HTParse(name, "", PARSE_PATH + PARSE_PUNCTUATION);
|
|
if (filename)
|
|
p = strrchr(filename, '/');
|
|
|
|
if (p && !*(p+1) && p != filename)
|
|
{
|
|
/* The URL was, in fact, malformed. I told you it was common. */
|
|
/* Fix up the URL and try again. */
|
|
p = strrchr(name, '/');
|
|
strncpy(buf, name, p - name);
|
|
buf[p - name] = '\0';
|
|
Dest_UpdateActual(pParams->request->destination, buf);
|
|
*pParams->pStatus = HT_REDIRECTION_ON_FLY;
|
|
GTR_FREE(filename);
|
|
return STATE_DONE;
|
|
}
|
|
GTR_FREE(filename);
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************/
|
|
|
|
pData = GTR_CALLOC(sizeof(*pData), 1);
|
|
if (!pData)
|
|
{ /* out of memory error! */
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
|
|
pData->request = pParams->request;
|
|
pData->pStatus = pParams->pStatus;
|
|
*ppInfo = pData;
|
|
GTR_FREE(pParams);
|
|
|
|
if (!pData->request)
|
|
{
|
|
*pData->pStatus = HT_INTERNAL;
|
|
return STATE_DONE;
|
|
}
|
|
|
|
pData->request->content_length = 0;
|
|
pData->iTotalBytes = 0;
|
|
pszURL = pData->request->destination->szActualURL;
|
|
|
|
|
|
/* get the local name, MIMEtype, encoding, etc... info for this URL */
|
|
switch (openType)
|
|
{
|
|
case 0: /* open local */
|
|
if (HTLoadFile_Async_SetFileInfo (tw, pData, pszURL, &pszLocalname) == STATE_DONE)
|
|
return STATE_DONE;
|
|
break;
|
|
|
|
case 1:
|
|
if (HTLoadDCache_Async_SetFileInfo (tw, pData, pszURL, &pszLocalname) == STATE_DONE)
|
|
return STATE_DONE;
|
|
break;
|
|
|
|
default:
|
|
/* guano case here -- we should never get here */
|
|
*pData->pStatus = -403;
|
|
ERR_ReportError(tw, SID_ERR_FILE_NOT_FOUND_S, pData->request->destination->szActualURL, NULL);
|
|
return STATE_DONE;
|
|
break;
|
|
}
|
|
|
|
if (tw)
|
|
tw->SDI_MimeType = 0; /* clear this now */
|
|
|
|
|
|
/****************************************/
|
|
#ifdef FEATURE_LOCAL_DIRECTORY
|
|
if (Dir_IsDirectory (pszLocalname))
|
|
{
|
|
*pData->pStatus = HTLoadDir (tw, pData->request, pszLocalname);
|
|
return STATE_DONE;
|
|
}
|
|
|
|
#endif
|
|
|
|
/* open the file */
|
|
pData->fp = fopen (pszLocalname, "rb");
|
|
if (!pData->fp)
|
|
{ /* unable to open the file */
|
|
GTR_FREE (pszLocalname);
|
|
pszLocalname = NULL;
|
|
pData->request->szLocalFileName = NULL;
|
|
*pData->pStatus = -403;
|
|
ERR_ReportError(tw, SID_ERR_FILE_NOT_FOUND_S, pData->request->destination->szActualURL, NULL);
|
|
return STATE_DONE;
|
|
}
|
|
|
|
pData->request->szLocalFileName = GTR_strdup (pszLocalname);
|
|
|
|
GTR_FREE (pszLocalname);
|
|
pszLocalname = NULL;
|
|
|
|
/* get the length of the data */
|
|
if (0 == fseek(pData->fp, 0, SEEK_END))
|
|
{
|
|
pData->request->content_length = ftell(pData->fp);
|
|
if (pData->request->content_length < 0)
|
|
{
|
|
pData->request->content_length = 0;
|
|
}
|
|
fseek(pData->fp, 0, SEEK_SET);
|
|
}
|
|
|
|
/* set the stream */
|
|
pData->stream = HTStreamStack(tw, pData->request->content_type, pData->request);
|
|
if (!pData->stream)
|
|
{
|
|
*pData->pStatus = -501;
|
|
return STATE_DONE;
|
|
}
|
|
|
|
/* Ignore CRLF if necessary */
|
|
if (!(pData->request->iFlags & HTREQ_BINARY) &&
|
|
((pData->request->content_encoding == HTAtom_for("7bit") ||
|
|
pData->request->content_encoding == HTAtom_for("8bit"))))
|
|
{
|
|
pData->stream = HTNetToText(pData->stream);
|
|
}
|
|
|
|
HTSetStreamStatus (tw, pData->stream, pData->request);
|
|
|
|
if (!pData->stream->isa->init_Async)
|
|
{
|
|
return STATE_FILE_COPYING;
|
|
}
|
|
else
|
|
{ /* the stream has an async initialization function */
|
|
pis = GTR_CALLOC (sizeof (*pis), 1);
|
|
if (!pis)
|
|
{ /* HEY - THE FILE SEEMS TO BE LEFT OPEN HERE!!! [der: 4/25/95] */
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
|
|
pis->me = pData->stream;
|
|
pis->request = pData->request;
|
|
pis->pResult = pData->pStatus;
|
|
|
|
Async_DoCall (pData->stream->isa->init_Async, pis);
|
|
return STATE_FILE_STREAMINIT;
|
|
}
|
|
} /* HTLoadFile_Async_Init */
|
|
|
|
|
|
/*****************************************************************************
|
|
HTLoadFile_Async_File_Copy
|
|
|
|
NOTE: This function also used by dcache functions
|
|
*****************************************************************************/
|
|
int
|
|
HTLoadFile_Async_File_Copy
|
|
(struct Mwin *tw,
|
|
struct Data_LoadFile *pData)
|
|
{
|
|
char input_buffer[INPUT_BUFFER_SIZE];
|
|
BOOL bError = FALSE;
|
|
BOOL bDone = FALSE;
|
|
int iNumBytesRead;
|
|
|
|
iNumBytesRead = fread(input_buffer, 1, INPUT_BUFFER_SIZE, pData->fp);
|
|
if (iNumBytesRead == 0)
|
|
{ /* EOF or error */
|
|
bDone = TRUE;
|
|
if (ferror(pData->fp) != 0)
|
|
{
|
|
bError = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pData->iTotalBytes += iNumBytesRead;
|
|
if (pData->request->content_length)
|
|
{
|
|
WAIT_SetTherm (tw, pData->iTotalBytes);
|
|
}
|
|
|
|
if (!(*pData->stream->isa->put_block)(pData->stream, input_buffer, iNumBytesRead))
|
|
{
|
|
bError = TRUE;
|
|
bDone = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!bDone && !bError)
|
|
{
|
|
return STATE_FILE_COPYING;
|
|
}
|
|
|
|
/* close the file */
|
|
fclose(pData->fp);
|
|
pData->fp = NULL;
|
|
|
|
/* cleanup -- abort (error) or free (success) */
|
|
if (bError)
|
|
{
|
|
(*pData->stream->isa->abort)(pData->stream, 0);
|
|
pData->stream = NULL;
|
|
*pData->pStatus = -1;
|
|
}
|
|
else
|
|
{
|
|
(*pData->stream->isa->free)(pData->stream);
|
|
pData->stream = NULL;
|
|
*pData->pStatus = HT_LOADED;
|
|
}
|
|
|
|
return STATE_DONE;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
HTLoadFile_Async_File_StreamInit
|
|
|
|
NOTE: This function also used by dcache functions
|
|
*****************************************************************************/
|
|
int
|
|
HTLoadFile_Async_File_StreamInit
|
|
(struct Mwin *tw,
|
|
struct Data_LoadFile *pData)
|
|
{
|
|
if (*pData->pStatus < 0)
|
|
{
|
|
(*pData->stream->isa->abort)(pData->stream, 0);
|
|
return STATE_DONE;
|
|
}
|
|
|
|
if (*pData->pStatus == 0)
|
|
{ /*
|
|
This only happens if the async init function told us we were already
|
|
done. In other words, only FileWriter should do this, and only when
|
|
request->szLocalFileName is true.
|
|
*/
|
|
fclose(pData->fp);
|
|
pData->fp = NULL;
|
|
(*pData->stream->isa->free)(pData->stream);
|
|
pData->stream = NULL;
|
|
*pData->pStatus = HT_LOADED;
|
|
return STATE_DONE;
|
|
}
|
|
|
|
return HTLoadFile_Async_File_Copy (tw, pData);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
HTLoadFile_Async_Abort
|
|
|
|
NOTE: This function also used by dcache functions
|
|
*****************************************************************************/
|
|
int
|
|
HTLoadFile_Async_Abort
|
|
(struct Mwin *tw,
|
|
struct Data_LoadFile *pData)
|
|
{
|
|
/* allow the stream to abort */
|
|
if (pData->stream)
|
|
{
|
|
(*pData->stream->isa->abort)(pData->stream, HTERROR_CANCELLED);
|
|
}
|
|
|
|
/* close the file if we opened it */
|
|
if (pData->fp)
|
|
{
|
|
fclose(pData->fp);
|
|
}
|
|
|
|
*pData->pStatus = -1;
|
|
return STATE_DONE;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
HTLoadFile_Async
|
|
|
|
This is a pretty pathetic async version -
|
|
once it starts copying it just keeps going.
|
|
*****************************************************************************/
|
|
PRIVATE int HTLoadFile_Async(struct Mwin *tw, int nState, void **ppInfo)
|
|
{
|
|
int result;
|
|
struct Data_LoadFile *pData;
|
|
|
|
pData = *ppInfo;
|
|
switch (nState)
|
|
{
|
|
case STATE_INIT:
|
|
result = HTLoadFile_Async_Init (tw, ppInfo, 0);
|
|
break;
|
|
|
|
case STATE_FILE_STREAMINIT:
|
|
result = HTLoadFile_Async_File_StreamInit (tw, pData);
|
|
break;
|
|
|
|
case STATE_FILE_COPYING:
|
|
result = HTLoadFile_Async_File_Copy (tw, pData);
|
|
break;
|
|
|
|
case STATE_ABORT:
|
|
result = HTLoadFile_Async_Abort (tw, pData);
|
|
break;
|
|
|
|
default:
|
|
XX_Assert((0), ("Function called with illegal state: %d", nState));
|
|
result = STATE_DONE;
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
HTLoadFile_TryFTP
|
|
*****************************************************************************/
|
|
static int
|
|
HTLoadFile_TryFTP
|
|
(struct Mwin *tw,
|
|
struct Data_LoadFile* pData,
|
|
char *addr)
|
|
{
|
|
char* newname = GTR_MALLOC(strlen(addr));
|
|
if (!newname)
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
|
|
strcpy(newname, "ftp:");
|
|
strcat(newname, addr + 5);
|
|
Dest_UpdateActual(pData->request->destination, newname);
|
|
GTR_FREE(newname);
|
|
*pData->pStatus = HT_REDIRECTION_ON_FLY;
|
|
return STATE_DONE;
|
|
}
|
|
|
|
|
|
static void file_MakeSizeString1 (char *buf, int nSize)
|
|
{
|
|
if (nSize >= 0)
|
|
{
|
|
if (nSize < 999)
|
|
{
|
|
sprintf(buf, "%ld", (long) nSize);
|
|
}
|
|
else if (nSize < 9999)
|
|
{
|
|
sprintf(buf, "%ld,%03ld", (long) nSize / 1000, (long) nSize % 1000);
|
|
}
|
|
else if (nSize < (999 * 1024))
|
|
{
|
|
sprintf(buf, "%ld", (long) nSize / 1024);
|
|
}
|
|
else
|
|
{
|
|
sprintf (buf, "%ld.%ld", (long) nSize / (1024 * 1024),
|
|
(long) (nSize / (1024 * 1024 / 10)) % 10);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strcpy(buf, "(unknown size?)");
|
|
}
|
|
}
|
|
|
|
static void file_MakeSizeString2(char *buf, int nSize)
|
|
{
|
|
if (nSize >= 0)
|
|
{
|
|
if (nSize < 999)
|
|
{
|
|
strcpy(buf, "bytes");
|
|
}
|
|
else if (nSize < 9999)
|
|
{
|
|
strcpy(buf, "bytes");
|
|
}
|
|
else if (nSize < (999 * 1024))
|
|
{
|
|
strcpy(buf, "KB");
|
|
}
|
|
else
|
|
{
|
|
strcpy (buf, "MB");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strcpy (buf, "unknown size");
|
|
}
|
|
}
|
|
|
|
#ifdef FEATURE_LOCAL_DIRECTORY
|
|
|
|
/*
|
|
** This function will read a directory and display
|
|
** the sorted entries in a <TABLE>
|
|
**
|
|
** Calls Dir_OpenDirectory() reading functions
|
|
** Calls HTML_new() to create the output
|
|
*/
|
|
|
|
|
|
int HTLoadDir (struct Mwin *tw, HTRequest *request, char *pszLocalname)
|
|
{
|
|
HTStructured *target;
|
|
int i;
|
|
#ifdef HTLOADDIR_USE_TABLE
|
|
char size_buf1[100];
|
|
char size_buf2[100];
|
|
#endif
|
|
char buf[_MAX_PATH+100];
|
|
HTBTree *bt; /* btree for sorting elements */
|
|
HTBTElement *ele;
|
|
|
|
CONST char *hrvalues[HTML_HR_ATTRIBUTES];
|
|
BOOL hrpresent[HTML_HR_ATTRIBUTES];
|
|
|
|
#ifdef HTLOADDIR_USE_TABLE
|
|
CONST char *tvalues[HTML_TABLE_ATTRIBUTES];
|
|
BOOL tpresent[HTML_TABLE_ATTRIBUTES];
|
|
|
|
CONST char *tdvalues[HTML_TD_ATTRIBUTES];
|
|
BOOL tdpresent[HTML_TD_ATTRIBUTES];
|
|
|
|
CONST char *trvalues[HTML_TR_ATTRIBUTES];
|
|
BOOL trpresent[HTML_TR_ATTRIBUTES];
|
|
#endif
|
|
|
|
void *dp; /* opendirectory private data */
|
|
HT_DirEntry *dir_ent;
|
|
char *p;
|
|
|
|
|
|
/****************************************/
|
|
/****************************************/
|
|
|
|
|
|
target = HTML_new (tw, request, NULL, WWW_HTML,
|
|
request->output_format, request->output_stream);
|
|
|
|
GTR_strncpy (buf, pszLocalname, _MAX_PATH);
|
|
p = buf + strlen(buf) - 1;
|
|
if (*p == '/')
|
|
*p = '\0';
|
|
HTDirTitles (target, buf, 1);
|
|
|
|
if (!(dp = Dir_OpenDirectory (buf)))
|
|
return HT_ERROR;
|
|
|
|
if (NULL == (bt = HTBTree_new ((HTComparer) strcasecomp)))
|
|
{
|
|
Dir_CloseDirectory (dp);
|
|
return HT_ERROR;
|
|
}
|
|
|
|
|
|
for (i = 0 ; i < HTML_HR_ATTRIBUTES ; i++)
|
|
hrpresent[i] = 0;
|
|
#ifdef HTLOADDIR_USE_TABLE
|
|
for (i = 0 ; i < HTML_TABLE_ATTRIBUTES ; i++)
|
|
tpresent[i] = 0;
|
|
for (i = 0 ; i < HTML_TD_ATTRIBUTES ; i++)
|
|
tdpresent[i] = 0;
|
|
for (i = 0 ; i < HTML_TR_ATTRIBUTES ; i++)
|
|
trpresent[i] = 0;
|
|
#endif
|
|
|
|
|
|
while ( Dir_NextEntry (dp,
|
|
dir_ent = (HT_DirEntry *)GTR_CALLOC (1, sizeof (*dir_ent))))
|
|
{
|
|
if ( dir_ent && dir_ent->name[0] && (strcmp (dir_ent->name, ".") && strcmp (dir_ent->name, "..")) )
|
|
HTBTree_add (bt, dir_ent);
|
|
}
|
|
|
|
(*target->isa->start_element) (target, HTML_HR, hrpresent, hrvalues);
|
|
|
|
#ifdef HTLOADDIR_USE_TABLE
|
|
tvalues[HTML_TABLE_CELLSPACING] = "50";
|
|
tpresent[HTML_TABLE_CELLSPACING] = 1;
|
|
/* start table */
|
|
(*target->isa->start_element) (target, HTML_TABLE, tpresent, tvalues);
|
|
#else
|
|
START (HTML_DIR);
|
|
#endif
|
|
|
|
for (ele = HTBTree_next(bt, NULL); ele != NULL; ele = HTBTree_next(bt, ele))
|
|
{
|
|
dir_ent = (HT_DirEntry *) HTBTree_object (ele);
|
|
|
|
#ifdef HTLOADDIR_USE_TABLE
|
|
/* Row */
|
|
(*target->isa->start_element) (target, HTML_TR, trpresent, trvalues);
|
|
/* Data Cell for directory info */
|
|
(*target->isa->start_element) (target, HTML_TD, tdpresent, tdvalues);
|
|
|
|
if (dir_ent->type & HTDIR_DIR)
|
|
//PUTS ("<DIR> ");
|
|
PUTS(GTR_GetString(SID_INF_DIR));
|
|
|
|
/* Column 2: file name */
|
|
(*target->isa->start_element) (target, HTML_TD, tdpresent, tdvalues);
|
|
HTDirEntry (target, request->destination->szActualURL, (CONST char *) dir_ent->name, 0);
|
|
|
|
/* toss in a couple colums for space */
|
|
(*target->isa->start_element) (target, HTML_TD, tdpresent, tdvalues);
|
|
(*target->isa->start_element) (target, HTML_TD, tdpresent, tdvalues);
|
|
|
|
/* size number */
|
|
tdvalues[HTML_TD_ALIGN] = "right";
|
|
tdpresent[HTML_TD_ALIGN] = 1;
|
|
(*target->isa->start_element) (target, HTML_TD, tdpresent, tdvalues);
|
|
file_MakeSizeString1 (size_buf1, dir_ent->size);
|
|
PUTS (size_buf1);
|
|
|
|
/* size units */
|
|
tdvalues[HTML_TD_ALIGN] = "left";
|
|
tdpresent[HTML_TD_ALIGN] = 1;
|
|
(*target->isa->start_element) (target, HTML_TD, tdpresent, tdvalues);
|
|
file_MakeSizeString2 (size_buf2, dir_ent->size);
|
|
PUTS (size_buf2);
|
|
|
|
tdpresent[HTML_TD_ALIGN] = 0; /* reset just in case */
|
|
|
|
END (HTML_TD);
|
|
END (HTML_TR);
|
|
#else
|
|
START (HTML_LI);
|
|
HTDirEntry (target, request->destination->szActualURL,
|
|
(CONST char *) dir_ent->name, 0);
|
|
#endif /* HTLOADDIR_USE_TABLE */
|
|
|
|
}
|
|
|
|
#ifdef HTLOADDIR_USE_TABLE
|
|
END (HTML_TABLE);
|
|
#else
|
|
END (HTML_DIR);
|
|
#endif
|
|
|
|
(*target->isa->free) (target); /* clean up stream */
|
|
HTBTreeAndObject_free (bt); /* free btree AND dir_ent's */
|
|
|
|
Dir_CloseDirectory (dp); /* close directory */
|
|
|
|
return HT_LOADED;
|
|
}
|
|
|
|
#endif /* FEATURE_LOCAL_DIRECTORY */
|
|
|
|
/*****************************************************************************
|
|
Protocol descriptors
|
|
*****************************************************************************/
|
|
GLOBALDEF PUBLIC HTProtocol HTFile ={"file", NULL, HTLoadFile_Async};
|