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.
 
 
 
 
 
 

583 lines
16 KiB

/*
Enhanced NCSA Mosaic from Spyglass
"Guitar"
Copyright 1994 Spyglass, Inc.
All Rights Reserved
Author(s):
Jim Seidman [email protected]
Portions of this file were derived from
the CERN libwww, version 2.15.
*/
#include "all.h"
#ifdef FEATURE_IAPI
HTList *protocols = NULL;
#else
PRIVATE HTList *protocols = NULL; /* List of registered protocol descriptors */
#endif
/* Create a request structure
** ---------------------------
*/
PUBLIC HTRequest *HTRequest_new(void)
{
HTRequest *me = (HTRequest *) GTR_CALLOC(1, sizeof(*me)); /* zero fill */
if (!me)
return NULL;
me->conversions = HTList_new(); /* No conversions registerd yet */
me->output_format = WWW_PRESENT; /* default it to present to user */
return me;
}
/* macro. calls HTRequest_new() and does some initing. */
PUBLIC HTRequest *HTRequest_init (HTAtom out_format)
{
HTRequest *me;
if (!(me = HTRequest_new()))
return NULL;
HTFormatInit (me->conversions);
me->output_format = out_format;
return me;
}
/* Delete a request structure
** --------------------------
*/
PUBLIC void HTRequest_delete(HTRequest * req)
{
if (req)
{
if (req->szLocalFileName)
{
GTR_FREE(req->szLocalFileName);
req->szLocalFileName = NULL;
}
HTFormatDelete(req->conversions);
GTR_FREE(req);
}
}
PRIVATE char *method_names[(int) MAX_METHODS + 1] =
{
"INVALID-METHOD",
"GET",
"POST",
"HEAD",
NULL
};
/* Get method enum value
** ---------------------
*/
PUBLIC HTMethod HTMethod_enum(char *name)
{
if (name)
{
int i;
for (i = 1; i < (int) MAX_METHODS; i++)
if (!strcmp(name, method_names[i]))
return (HTMethod) i;
}
return METHOD_INVALID;
}
/* Get method name
** ---------------
*/
PUBLIC char *HTMethod_name(HTMethod method)
{
if ((int) method > (int) METHOD_INVALID &&
(int) method < (int) MAX_METHODS)
return method_names[(int) method];
else
return method_names[(int) METHOD_INVALID];
}
/* Register a Protocol HTRegisterProtocol
** -------------------
*/
PUBLIC BOOL HTRegisterProtocol(HTProtocol * protocol)
{
if (!protocols)
protocols = HTList_new();
HTList_addObject(protocols, protocol);
return YES;
}
/* Register all known protocols
** ----------------------------
**
** Add to or subtract from this list if you add or remove protocol modules.
** This routine is called the first time the protocol list is needed,
** unless any protocols are already registered, in which case it is not called.
** Therefore the application can override this list.
**
** Compiling with NO_INIT prevents all known protocols from being forced
** in at link time.
*/
#ifdef _GIBRALTAR
void HTAccessInit(void) /* Call me once */
{
GLOBALREF HTProtocol HTTP, HTFile;
#if defined(FEATURE_INLINE_MAIL) || defined(_USE_MAPI)
GLOBALREF HTProtocol HTMailTo;
#endif
GLOBALREF HTProtocol HTFTP, HTGopher;
#ifdef FEATURE_SSL
GLOBALREF HTProtocol HTTPS;
#endif
#ifdef FEATURE_PROTOCOL_HELPER
GLOBALREF HTProtocol HTtdk;
#endif
#ifdef SHTTP_ACCESS_TYPE
GLOBALREF HTProtocol SHTTP;
HTRegisterProtocol(&SHTTP);
#endif
#if defined(FEATURE_INLINE_MAIL) || defined(_USE_MAPI)
HTRegisterProtocol(&HTMailTo);
#endif
HTRegisterProtocol(&HTGopher);
HTRegisterProtocol(&HTFile);
HTRegisterProtocol(&HTFTP);
HTRegisterProtocol(&HTTP);
#ifdef FEATURE_SSL
HTRegisterProtocol(&HTTPS);
#endif
#ifdef FEATURE_PROTOCOL_HELPER
HTRegisterProtocol(&HTtdk);
#endif
}
#else /* _GIBRALTAR
void HTAccessInit(void) /* Call me once */
{
GLOBALREF HTProtocol HTTP, HTFile, HTTelnet, HTTn3270, HTRlogin;
#ifdef FEATURE_SSL
GLOBALREF HTProtocol HTTPS;
#endif
#if defined(FEATURE_INLINE_MAIL) || defined(_USE_MAPI)
GLOBALREF HTProtocol HTMailTo;
#endif
GLOBALREF HTProtocol HTFTP, HTNews, HTGopher;
#ifdef FEATURE_PROTOCOL_HELPER
GLOBALREF HTProtocol HTtdk;
#endif
#ifdef SHTTP_ACCESS_TYPE
GLOBALREF HTProtocol SHTTP;
HTRegisterProtocol(&SHTTP);
#endif
HTRegisterProtocol(&HTTn3270);
HTRegisterProtocol(&HTRlogin);
HTRegisterProtocol(&HTTelnet);
#if defined(FEATURE_INLINE_MAIL) || defined(_USE_MAPI)
HTRegisterProtocol(&HTMailTo);
#endif
HTRegisterProtocol(&HTNews);
HTRegisterProtocol(&HTGopher);
HTRegisterProtocol(&HTFile);
HTRegisterProtocol(&HTFTP);
HTRegisterProtocol(&HTTP);
#ifdef FEATURE_SSL
HTRegisterProtocol(&HTTPS);
#endif
#ifdef FEATURE_PROTOCOL_HELPER
HTRegisterProtocol(&HTtdk);
#endif
}
#endif /* !_GIBRALTAR */
void HTDisposeProtocols(void)
{
if (protocols)
{
HTList_delete(protocols);
}
}
struct _HTStream
{
CONST HTStreamClass *isa;
};
int HTViewSource_Load(HTRequest * request, struct Mwin *tw)
{
HTStream *stream;
stream = HTStreamStack(tw, HTAtom_for("text/plain"), request);
if (stream)
{
stream->isa->put_block(stream, CS_GetPool(request->myCharStream), CS_GetLength(request->myCharStream));
stream->isa->free(stream);
return HT_LOADED;
}
else
{
return -1;
}
}
GLOBALDEF PUBLIC HTProtocol HTViewSourceProtocol = {"_viewsource_", HTViewSource_Load, NULL};
/* Find the protocol for a given request */
static HTProtocol *x_GetProtocol(HTRequest *request, struct DestInfo *pdi)
{
char szProt[MAX_PROT_LEN + 1];
char *pColon;
HTList *cur;
HTProtocol *p;
#ifndef NO_INIT
if (!protocols)
HTAccessInit();
#endif
if (!pdi->szActualURL)
return NULL;
if (request->myCharStream)
{
return &HTViewSourceProtocol;
}
if (gPrefs.bEnableDiskCache && (!(request->iFlags & HTREQ_RELOAD)))
{
struct CacheFileInformation *cfi;
cfi = DCACHE_CheckForCachedURL(pdi->szActualURL, NULL, NULL, NULL);
if (cfi)
{
/*
We have the object in the cache
*/
if (!cfi->bDynamic)
{
/* It's not in the main cache -- use it no matter what */
return &HTDCache;
}
if (gPrefs.dcache_verify_policy == 0)
{
/* a verify_policy of 0 means never check the Last-Modified date */
return &HTDCache;
}
if (request->iFlags & HTREQ_PREFERCACHE)
{
/* if this bit is set, then we're being told to use the cache */
return &HTDCache;
}
if ((gPrefs.dcache_verify_policy == 1) && (cfi->bVerifiedThisSession))
{
/*
a verify policy of 1 means check the Last-Modified date once per
session, but it's already been checked for this object this session,
so we use the cached object.
*/
return &HTDCache;
}
/*
If we get here, then the object is in the cache, but we need to verify it.
This means we need to contact the HTTP server, get the Last-Modified header
for this object, and compare it against cfi->tLastModified. If the cached
version is still current, we should use it. Otherwise, we should use the current
version off the net, and replace the cached version with the current version
off the net.
*/
}
else
{
char *pAliasURL;
pAliasURL = DCACHE_CheckForRuleMatch(pdi->szActualURL, NULL, NULL, NULL);
if (pAliasURL)
{
GTR_FREE(pAliasURL);
return &HTDCache;
}
}
}
if (pdi->use_proxy)
{
strcpy(szProt, "http"); /* We only support http-based proxy servers */
}
else
{
pColon = strchr(pdi->szActualURL, ':');
if (!pColon || (pColon - pdi->szActualURL > MAX_PROT_LEN))
{
return NULL;
}
else
{
strncpy(szProt, pdi->szActualURL, pColon - pdi->szActualURL);
szProt[pColon - pdi->szActualURL] = '\0';
}
}
cur = protocols;
while ((p = (HTProtocol *) HTList_nextObject(cur)))
{
if (strcmp(p->name, szProt) == 0)
{
break;
}
}
return p;
}
/* Load a document
** ---------------
**
** This is an internal routine, which has an address AND a matching
** anchor. (The public routines are called with one OR the other.)
**
** On entry,
** request->
** anchor a parent anchor with fully qualified
** hypertext reference as its address set
** output_format valid
** output_stream valid on NULL
**
** On exit,
** returns <0 Error has occured.
** HT_LOADED Success
** HT_NO_DATA Success, but no document loaded.
** (telnet sesssion started etc)
**
*/
static int HTLoad_Async(struct Mwin *tw, int nState, void **ppInfo)
{
struct Params_LoadAsync *pParams;
char *arg = NULL;
HTProtocol *p;
pParams = *ppInfo;
if (nState == STATE_INIT)
{
if (pParams->request->method == METHOD_INVALID)
pParams->request->method = METHOD_GET;
p = x_GetProtocol(pParams->request, pParams->request->destination);
if (!p)
{
ERR_ReportError(tw, SID_ERR_PROTOCOL_NOT_SUPPORTED_S, pParams->request->destination->szActualURL, NULL);
*pParams->pStatus = HT_LOADED; /* Avoid double error-message */
return STATE_DONE;
}
if (!p->load_async)
{
/* This is a temporary hack - since this protocol doesn't have an
async version, load it synchronously. */
#if defined(UNIX) || defined(WIN32)
/* TW added so we can get window information. */
/* This is really a hack cuz currently only
** sdi_Custom_Protocol_Handler() accepts 2 args. This
** will probably not run on an interpretter, but hopefully
** will work for now. -dpg (of course)
*/
*pParams->pStatus =
(* ((int (*) (HTRequest * request, struct Mwin *)) p->load))
(pParams->request, tw);
#else
*pParams->pStatus = (*(p->load))(pParams->request, tw);
#endif
return STATE_DONE;
}
else
{
Async_DoCall(p->load_async, pParams);
*ppInfo = NULL; /* Avoid having it get freed */
}
}
return STATE_DONE;
}
/* Loads a document when we need finer control over redirection and such (e.g. so we
can check if a document we're redirected to is in our cache). */
int HTLoadSpecial_Async(struct Mwin *tw, int nState, void **ppInfo)
{
struct Params_LoadAsync *pParams;
pParams = *ppInfo;
if (nState == STATE_INIT)
{
if (!pParams->request->destination->szActualURL || !*pParams->request->destination->szActualURL)
{
*pParams->pStatus = NO;
}
else
{
XX_DMsg(DBG_WWW, ("HTAccess: loading document %s\n", pParams->request->destination->szActualURL));
if (!pParams->request->output_format)
pParams->request->output_format = WWW_PRESENT;
Async_DoCall(HTLoad_Async, pParams);
*ppInfo = NULL; /* Avoid having it freed - it belongs to HTLoad_Async now */
}
}
return STATE_DONE;
}
/*
Load a document with automatic handling of redirection
On Entry,
request->anchor valid for of the document to be accessed.
request->childAnchor optional anchor within doc to be selected
request->anchor is the node_anchor for the document
request->output_format is valid
On Exit,
*pStatus == 0 Load failed
*pStatus != 0 Load succeeded
*/
#define STATE_LOADDOC_TRIED (STATE_OTHER)
int HTLoadDocument_Async(struct Mwin *tw, int nState, void **ppInfo)
{
struct Params_LoadAsync *pParams;
pParams = *ppInfo;
switch (nState)
{
case STATE_INIT:
/* Save a pointer to the original request in case we wind up doing a
redirection. */
pParams->extra = pParams->request;
if (!pParams->request->destination->szActualURL || !*pParams->request->destination->szActualURL)
{
XX_DMsg(DBG_WWW, ("HTLoadDocument_Async called with empty anchor address!\n"));
*pParams->pStatus = NO;
return STATE_DONE;
}
else
{
struct Params_LoadAsync *p2;
XX_DMsg(DBG_WWW, ("HTAccess: loading document %s\n", pParams->request->destination->szActualURL));
if (!pParams->request->output_format)
pParams->request->output_format = WWW_PRESENT;
/* HTLoad_Async takes a set of parameters identical to ours. */
p2 = GTR_MALLOC(sizeof(*p2));
if (p2)
{
memcpy(p2, pParams, sizeof(*p2));
Async_DoCall(HTLoad_Async, p2);
return STATE_LOADDOC_TRIED;
}
else
{
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
return STATE_ABORT;
}
}
case STATE_LOADDOC_TRIED:
/* If we created a new request structure, release it */
if (pParams->extra != pParams->request)
{
HTRequest_delete(pParams->request);
pParams->request = NULL;
}
if (*pParams->pStatus == HT_NO_DATA)
{
XX_DMsg(DBG_WWW, ("HTLoad_Async returned HT_NO_DATA\n"));
*pParams->pStatus = NO;
return STATE_DONE;
}
else if (*pParams->pStatus == HT_LOADED)
{
XX_DMsg(DBG_WWW, ("HTLoad_Async returned HT_LOADED\n"));
*pParams->pStatus = YES;
return STATE_DONE;
}
else if (*pParams->pStatus == HT_REDIRECTION_ON_FLY)
{
HTRequest *initial_request;
struct Params_LoadAsync *p2;
initial_request = pParams->extra;
XX_DMsg(DBG_WWW, ("HTLoad_Async returned redirection to %s\n", initial_request->destination->szActualURL));
pParams->request = HTRequest_new();
HTFormatInit(pParams->request->conversions);
pParams->request->output_format = initial_request->output_format;
pParams->request->destination = initial_request->destination;
/* HTLoad_Async takes a set of parameters identical to ours. */
p2 = GTR_MALLOC(sizeof(*p2));
if (p2)
{
memcpy(p2, pParams, sizeof(*p2));
Async_DoCall(HTLoad_Async, p2);
return STATE_LOADDOC_TRIED;
}
else
{
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
return STATE_ABORT;
}
}
else if (*pParams->pStatus <= 0)
{
*pParams->pStatus = NO;
return STATE_DONE;
}
else
{
XX_Assert(0, ("Illegal return value from HTLoad_Async! (%d)", *pParams->pStatus));
*pParams->pStatus = NO;
}
case STATE_ABORT:
/* If we created a new request structure, release it */
if (pParams->extra != pParams->request)
{
HTRequest_delete(pParams->request);
}
*pParams->pStatus = NO;
return STATE_DONE;
}
XX_Assert((0), ("Function called with illegal state: %d", nState));
return STATE_DONE;
}
#ifdef FEATURE_IAPI
PUBLIC BOOL HTUnregisterProtocol(HTProtocol * protocol)
{
if (!protocols)
return YES;
HTList_removeObject(protocols, protocol);
return YES;
}
#endif