Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

576 lines
14 KiB

/*
This file was derived from the libwww code, version 2.15, from CERN.
A number of modifications have been made by Spyglass.
[email protected]
*/
#include "all.h"
#include <shellapi.h>
#include "mime.h"
#ifdef FEATURE_INTL
#define IEXPLORE
#include <fechrcnv.h>
#endif
#include "history.h"
struct _HTStructured
{
CONST HTStructuredClass *isa;
/* ... */
};
struct _HTStream
{
CONST HTStreamClass *isa;
/* ... */
};
/* Controlling globals
**
*/
PUBLIC HTFormat HTFileFormat(CONST char *filename, PENCODING 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, '.');
if (p)
{
HTAtom atomMIMEType;
XX_DMsg(DBG_WWW, ("HTFileFormat: Looking for extension %s... ", p));
if (MIME_GetMIMEAtomFromExtension(pslash, &atomMIMEType))
{
XX_DMsg(DBG_WWW, ("found! MIME=%s\n", HTAtom_name(atomMIMEType)));
if (pencoding)
*pencoding = MIME_GetEncoding(atomMIMEType);
return atomMIMEType;
}
XX_DMsg(DBG_WWW, ("Suffix not found.\n"));
if (pencoding)
*pencoding = ENCODING_BINARY;
return HTAtom_for("application/octet-stream");
}
else
{
if (pencoding)
*pencoding = 0;
return HTAtom_for("text/plain");
}
}
/* 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
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;
}
#endif
#ifdef WIN32
#define SLASH '\\'
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;
}
struct Data_LoadFile {
HTRequest * request;
int * pStatus; /* Where to store the status return */
FILE * fp;
HTStream * stream;
BOOL ref_filename_accepted;
};
#define STATE_FILE_STREAMINIT (STATE_OTHER + 1)
#define STATE_FILE_COPYING (STATE_OTHER + 2)
/* 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)
{
CONST char *addr;
char *filename;
char *access;
HTFormat format;
char *newname = 0; /* Simplified name of file */
ENCODING encoding;
HTAtom language;
char *localname;
struct Params_LoadAsync *pParams;
struct Data_LoadFile *pData;
pData = *ppInfo;
switch (nState)
{
case STATE_INIT:
pParams = *ppInfo;
pData = GTR_MALLOC(sizeof(*pData));
memset(pData, 0, sizeof(*pData));
pData->request = HTRequest_validate(pParams->request);
pData->pStatus = pParams->pStatus;
pData->ref_filename_accepted = FALSE;
*ppInfo = pData;
GTR_FREE(pParams);
if (!pData->request)
{
*pData->pStatus = HT_INTERNAL;
return STATE_DONE;
}
pData->request->content_length = 0;
/* Reduce the filename to a basic form (hopefully unique!)
*/
addr = pData->request->destination->szActualURL;
newname = GTR_strdup(addr);
filename = HTParse(newname, "", PARSE_PATH | PARSE_PUNCTUATION);
/* If access is ftp => go directly to ftp code (henrik 27/02-94) */
access = HTParse(newname, "", PARSE_ACCESS);
if (!strcmp("ftp", access))
{
if (newname)
{
GTR_FREE(newname);
newname = NULL;
}
if (access)
{
GTR_FREE(access);
access = NULL;
}
if (filename)
{
GTR_FREE(filename); /* Not used anymore */
filename = NULL;
}
goto try_ftp;
}
else
{
if (newname)
{
GTR_FREE(newname);
newname = NULL;
}
if (access)
{
GTR_FREE(access);
access = NULL;
}
}
format = HTFileFormat(filename, &encoding, &language);
pData->request->content_type = format;
pData->request->content_encoding = encoding;
pData->request->content_language = language;
pData->request->szLocalFileName = NULL;
if (filename)
{
GTR_FREE(filename);
filename = NULL;
}
localname = HTLocalName(addr);
/* Need protection here for telnet server but not httpd server */
if (localname)
{ /* try local file system */
localname = AdjustLocalNameIfRelative( tw, localname );
//
// Now adjust the doc's ActualURL to an absolute form so that
// subsequent relative paths will work
//
{
char *filename_part;
char *source_to_use = localname;
char temp_fpn[MAX_PATH+1];
//
// First, get canonical name (removes embedded ..'s)
//
if (GetFullPathName(localname, MAX_PATH + 1, temp_fpn,
&filename_part))
source_to_use = temp_fpn;
GTR_FREE(pData->request->destination->szActualURL);
pData->request->destination->szActualURL =
(char *) GTR_MALLOC( 5 + strlen(source_to_use) + 1 );
strcpy( pData->request->destination->szActualURL, "file:" );
strcat( pData->request->destination->szActualURL, source_to_use );
pData->request->szLocalFileName = GTR_strdup(localname);
}
pData->fp = fopen(localname, "rb");
if (pData->fp)
{ /* Good! */
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);
}
// SNIFF the data, to see if we think we can second guess the file type
{
char input_buffer[1024];
int bytes = pData->request->content_length;
BOOL bEOF = TRUE;
if (bytes > 1024)
{
bytes = 1024;
bEOF = FALSE;
}
bytes = fread(input_buffer, 1, bytes, pData->fp);
if (bytes > 0)
{
HTRecognizeMimeData(input_buffer,
bytes,
&format,
pData->request,
bEOF);
}
fseek(pData->fp, 0, SEEK_SET);
}
pData->stream = HTStreamStack(tw, format, pData->request);
if (!pData->stream)
{
if ( pData->request->iFlags & HTREQ_NULL_STREAM_IS_OK )
{
pData->request->iFlags &= ~HTREQ_NULL_STREAM_IS_OK;
*pData->pStatus = HT_LOADED;
}
else
*pData->pStatus = -501;
GTR_FREE(localname);
return STATE_DONE;
}
else
{
/* Ignore CRLF if necessary
*/
if (! (pData->request->iFlags & HTREQ_BINARY) &&
(pData->request->content_encoding == ENCODING_7BIT ||
pData->request->content_encoding == ENCODING_8BIT))
pData->stream = HTNetToText(pData->stream);
HTSetStreamStatus(tw, pData->stream, pData->request);
if (pData->stream->isa->io_control)
pData->ref_filename_accepted =
(*pData->stream->isa->io_control)(
pData->stream,
HTS_IOCTL_FILE_BY_REF,
localname);
GTR_FREE(localname);
if (pData->stream->isa->init_Async)
{
/* The stream has an async initialization function that needs to be called
(probably to put up a dialog) before we continue. */
struct Params_InitStream *pis;
pis = GTR_MALLOC(sizeof(*pis));
pis->me = pData->stream;
pis->request = pData->request;
pis->pResult = pData->pStatus;
pis->fDCache = FALSE; //Don't cache to disk
Async_DoCall(pData->stream->isa->init_Async, pis);
return STATE_FILE_STREAMINIT;
}
else
return STATE_FILE_COPYING;
}
}
else
{
//
// If we can't open it, it either doesn't exist, or is a
// directory, or is opened exclusive by someone else.
//
if ( FExistsDir(localname, FALSE, FALSE) ) {
// It's a directory, so let's ShellExecute it...
HINSTANCE shellex_result
= ShellExecute( NULL, NULL, localname, NULL, NULL, SW_SHOW );
if ( (UINT) shellex_result > 32 )
{
*pData->pStatus = HT_LOADED;
GTR_FREE(localname);
return STATE_DONE;
}
}
}
}
try_ftp:
/* Now, as transparently mounted access has failed, we try FTP.
*/
{
char *newname = NULL;
char *myhost;
BOOL bTryFTP;
bTryFTP = FALSE;
myhost = HTParse(addr, "", PARSE_HOST);
if (myhost && *myhost)
{
bTryFTP = TRUE;
}
if (myhost)
{
GTR_FREE(myhost);
}
if (bTryFTP)
{
newname = GTR_MALLOC(strlen(addr));
strcpy(newname, "ftp:");
strcat(newname, addr + 5);
Dest_UpdateActual(pData->request->destination, newname,FALSE);
GTR_FREE(newname);
*pData->pStatus = HT_REDIRECTION_ON_FLY;
return STATE_DONE;
}
}
/* All attempts have failed.
*/
*pData->pStatus = -403;
// <CMF> I don't think this should be reported here
// ERR_ReportError(tw, errFileURLNotFound, pData->request->destination->szActualURL, "");
return STATE_DONE;
case STATE_FILE_STREAMINIT:
if (*pData->pStatus < 0)
{
(*pData->stream->isa->abort)(pData->stream, 0);
return STATE_DONE;
}
/* else fall through to STATE_FILE_COPYING */
case STATE_FILE_COPYING:
{
int bytes = 0;
int status = 0;
char input_buffer[INPUT_BUFFER_SIZE];
#ifdef FEATURE_INTL
// BUGBUG:I have to revisit this to make sure
//every case is covered here.
// _BUGBUG Perf: should load fechrcnv.dll on demand.
if ((pData->request != NULL && pData->request->iMimeCharSet != -1 && aMimeCharSet[pData->request->iMimeCharSet].iChrCnv)
|| (tw != NULL && aMimeCharSet[tw->iMimeCharSet].iChrCnv))
FCC_Init();
#endif
if ( (pData->request->iFlags & HTREQ_DOING_SAVE_FILE)
|| !pData->ref_filename_accepted )
{
while (1)
{
status = fread(input_buffer, 1, INPUT_BUFFER_SIZE, pData->fp);
if (status == 0)
{ /* EOF or error */
if (ferror(pData->fp) != 0)
status = -1;
break;
}
bytes += status;
if (pData->request->content_length)
WAIT_SetTherm(tw, bytes);
(*pData->stream->isa->put_block)(pData->stream, input_buffer, status, FALSE);
}
}
fclose(pData->fp);
pData->fp = NULL;
if (status < 0)
{
(*pData->stream->isa->abort)(pData->stream, 0);
pData->stream = NULL;
*pData->pStatus = -1;
}
else
{
DCACHETIME dct={0,0};
(*pData->stream->isa->free)(pData->stream, dct, dct);
pData->stream = NULL;
*pData->pStatus = HT_LOADED;
}
return STATE_DONE;
}
case STATE_ABORT:
pData->request = HTRequest_validate(pData->request);
if (pData->stream)
{
(*pData->stream->isa->abort)(pData->stream, HTERROR_CANCELLED);
}
if (pData->fp)
{
fclose(pData->fp);
}
*pData->pStatus = -1;
return STATE_DONE;
}
XX_Assert((0), ("Function called with illegal state: %d", nState));
return STATE_DONE;
}
/* Protocol descriptors
*/
GLOBALDEF PUBLIC HTProtocol HTFile ={"file", NULL, HTLoadFile_Async};