Minor casts to silence compiler.
/*
* The contents of this file are subject to the AOLserver Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://aolserver.com/.
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is AOLserver Code and related documentation
* distributed by AOL.
*
* The Initial Developer of the Original Code is America Online,
* Inc. Portions created by AOL are Copyright (C) 1999 America Online,
* Inc. All Rights Reserved.
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU General Public License (the "GPL"), in which case the
* provisions of GPL are applicable instead of those above. If you wish
* to allow use of your version of this file only under the terms of the
* GPL and not to allow others to use your version of this file under the
* License, indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by the GPL.
* If you do not delete the provisions above, a recipient may use your
* version of this file under either the License or the GPL.
*/
/*
* fastpath.c --
*
* Get page possibly from a file cache.
*/
static const char *RCSID = "@(#) $Header: /cvsroot/aolserver/aolserver/nsd/fastpath.c,v 1.22 2005/01/15 23:54:08 jgdavidson Exp $, compiled: " __DATE__ " " __TIME__;
#include "nsd.h"
/*
* The following constants are defined for this file
*/
#ifdef MAP_FAILED
#undef MAP_FAILED
#endif
#define MAP_FAILED ((void *) (-1))
/*
* The following structure defines the contents of a file
* stored in the file cache.
*/
typedef struct {
time_t mtime;
int size;
int refcnt;
char bytes[1]; /* Grown to actual file size. */
} File;
/*
* Local functions defined in this file
*/
static Ns_Callback FreeEntry;
static void DecrEntry(File *);
static int UrlIs(char *server, char *url, int dir);
static int FastStat(char *file, struct stat *stPtr);
static int FastReturn(NsServer *servPtr, Ns_Conn *conn, int status,
char *type, char *file, struct stat *stPtr);
/*
*----------------------------------------------------------------------
* NsFastpathCache --
*
* Initialize the fastpath cache.
*
* Results:
* Pointer to Ns_Cache.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
Ns_Cache *
NsFastpathCache(char *server, int size)
{
Ns_DString ds;
Ns_Cache *fpCache;
int keys;
#ifdef _WIN32
keys = TCL_STRING_KEYS;
#else
keys = FILE_KEYS;
#endif
Ns_DStringInit(&ds);
Ns_DStringVarAppend(&ds, "nsfp:", server, NULL);
fpCache = Ns_CacheCreateSz(ds.string, keys, (size_t) size, FreeEntry);
Ns_DStringFree(&ds);
return fpCache;
}
/*
*----------------------------------------------------------------------
*
* Ns_ConnReturnFile --
*
* Send the contents of a file out the conn.
*
* Results:
* NS_OK/NS_ERROR
*
* Side effects:
* See FastReturn.
*
*----------------------------------------------------------------------
*/
int
Ns_ConnReturnFile(Ns_Conn *conn, int status, char *type, char *file)
{
struct stat st;
char *server;
NsServer *servPtr;
if (!FastStat(file, &st)) {
return Ns_ConnReturnNotFound(conn);
}
server = Ns_ConnServer(conn);
servPtr = NsGetServer(server);
return FastReturn(servPtr, conn, status, type, file, &st);
}
/*
*----------------------------------------------------------------------
* Ns_PageRoot --
*
* Return path name of the server pages directory.
*
* Results:
* Server pageroot or NULL on invalid server.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
char *
Ns_PageRoot(char *server)
{
NsServer *servPtr = NsGetServer(server);
return servPtr->fastpath.pageroot;
}
/*
*----------------------------------------------------------------------
* Ns_SetUrlToFileProc --
*
* Set pointer to custom routine that acts like Ns_UrlToFile();
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Ns_SetUrlToFileProc(char *server, Ns_UrlToFileProc *procPtr)
{
NsServer *servPtr = NsGetServer(server);
servPtr->fastpath.url2file = procPtr;
}
/*
*----------------------------------------------------------------------
* Ns_UrlToFile --
*
* Construct the filename that corresponds to a URL.
*
* Results:
* Return NS_OK on success or NS_ERROR on failure.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Ns_UrlToFile(Ns_DString *dsPtr, char *server, char *url)
{
NsServer *servPtr = NsGetServer(server);
return NsUrlToFile(dsPtr, servPtr, url);
}
/*
*----------------------------------------------------------------------
* Ns_UrlIsFile, Ns_UrlIsDir --
*
* Check if a file/directory that corresponds to a URL exists.
*
* Results:
* Return NS_TRUE if the file exists and NS_FALSE otherwise.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Ns_UrlIsFile(char *server, char *url)
{
return UrlIs(server, url, 0);
}
int
Ns_UrlIsDir(char *server, char *url)
{
return UrlIs(server, url, 1);
}
static int
UrlIs(char *server, char *url, int dir)
{
Ns_DString ds;
int is = NS_FALSE;
struct stat st;
Ns_DStringInit(&ds);
if (Ns_UrlToFile(&ds, server, url) == NS_OK &&
(stat(ds.string, &st) == 0) &&
((dir && S_ISDIR(st.st_mode)) ||
(dir == NS_FALSE && S_ISREG(st.st_mode)))) {
is = NS_TRUE;
}
Ns_DStringFree(&ds);
return is;
}
/*
*----------------------------------------------------------------------
* FastGetRestart --
*
* Construct the full URL and redirect internally.
*
* Results:
* See Ns_ConnRedirect().
*
* Side effects:
* See Ns_ConnRedirect().
*
*----------------------------------------------------------------------
*/
static int
FastGetRestart(Ns_Conn *conn, char *page)
{
int status;
Ns_DString ds;
Ns_DStringInit(&ds);
Ns_MakePath(&ds, conn->request->url, page, NULL);
status = Ns_ConnRedirect(conn, ds.string);
Ns_DStringFree(&ds);
return status;
}
/*
*----------------------------------------------------------------------
* NsFastGet --
*
* Return the contents of a URL.
*
* Results:
* Return NS_OK for success or NS_ERROR for failure.
*
* Side effects:
* Contents of file may be cached in file cache.
*
*----------------------------------------------------------------------
*/
int
NsFastGet(void *arg, Ns_Conn *conn)
{
Ns_DString ds;
NsServer *servPtr = arg;
char *url = conn->request->url;
int result, i;
struct stat st;
Ns_DStringInit(&ds);
if (NsUrlToFile(&ds, servPtr, url) != NS_OK
|| !FastStat(ds.string, &st)) {
goto notfound;
}
if (S_ISREG(st.st_mode)) {
/*
* Return ordinary files as with Ns_ConnReturnFile.
*/
result = FastReturn(servPtr, conn, 200, NULL, ds.string, &st);
} else if (S_ISDIR(st.st_mode)) {
/*
* For directories, search for a matching directory file and
* restart the connection if found.
*/
for (i = 0; i < servPtr->fastpath.dirc; ++i) {
Ns_DStringTrunc(&ds, 0);
if (NsUrlToFile(&ds, servPtr, url) != NS_OK) {
goto notfound;
}
Ns_DStringVarAppend(&ds, "/", servPtr->fastpath.dirv[i], NULL);
if ((stat(ds.string, &st) == 0) && S_ISREG(st.st_mode)) {
if (url[strlen(url) - 1] != '/') {
Ns_DStringTrunc(&ds, 0);
Ns_DStringVarAppend(&ds, url, "/", NULL);
result = Ns_ConnReturnRedirect(conn, ds.string);
} else {
result = FastGetRestart(conn, servPtr->fastpath.dirv[i]);
}
goto done;
}
}
/*
* If no index file was found, invoke a directory listing
* ADP or Tcl proc if configured.
*/
if (servPtr->fastpath.diradp != NULL) {
result = Ns_AdpRequest(conn, servPtr->fastpath.diradp);
} else if (servPtr->fastpath.dirproc != NULL) {
result = Ns_TclRequest(conn, servPtr->fastpath.dirproc);
} else {
goto notfound;
}
} else {
notfound:
result = Ns_ConnReturnNotFound(conn);
}
done:
Ns_DStringFree(&ds);
return result;
}
/*
*----------------------------------------------------------------------
* FreeEntry --
*
* Logically remove a cached file from file cache.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
FreeEntry(void *arg)
{
File *filePtr = (File *) arg;
DecrEntry(filePtr);
}
/*
*----------------------------------------------------------------------
* DecrEntry --
*
* Decrement reference count of cached file.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
DecrEntry(File *filePtr)
{
if (--filePtr->refcnt == 0) {
ns_free(filePtr);
}
}
/*
*----------------------------------------------------------------------
*
* FastStat --
*
* Stat a file, logging an error on unexpected results.
*
* Results:
* 1 if stat ok, 0 otherwise.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
FastStat(char *file, struct stat *stPtr)
{
if (stat(file, stPtr) != 0) {
if (errno != ENOENT && errno != EACCES) {
Ns_Log(Error, "fastpath: stat(%s) failed: %s",
file, strerror(errno));
}
return 0;
}
return 1;
}
/*
*----------------------------------------------------------------------
*
* FastReturn --
*
* Return an open file, possibly from cache.
*
* Results:
* Standard Ns_Request result.
*
* Side effects:
* May map, cache, open, and/or send file out connection.
*
*----------------------------------------------------------------------
*/
static int
FastReturn(NsServer *servPtr, Ns_Conn *conn, int status,
char *type, char *file, struct stat *stPtr)
{
int result = NS_ERROR, fd, new, nread;
File *filePtr;
char *key;
Ns_Entry *entPtr;
#ifndef _WIN32
char *map;
FileKey ukey;
#endif
/*
* Determine the mime type if not given.
*/
if (type == NULL) {
type = Ns_GetMimeType(file);
}
/*
* Set the last modified header if not set yet and, if not
* modified since last request, return now.
*/
Ns_ConnSetLastModifiedHeader(conn, &stPtr->st_mtime);
if (Ns_ConnModifiedSince(conn, stPtr->st_mtime) == NS_FALSE) {
return Ns_ConnReturnNotModified(conn);
}
/*
* For no output (i.e., HEAD request), just send required
* headers.
*/
if (conn->flags & NS_CONN_SKIPBODY) {
Ns_ConnSetRequiredHeaders(conn, type, (int) stPtr->st_size);
return Ns_ConnFlushHeaders(conn, status);
}
if (servPtr->fastpath.cache == NULL
|| stPtr->st_size > servPtr->fastpath.cachemaxentry) {
/*
* Caching is disabled or the entry is too large for the cache
* so just open, mmap, and send the content directly.
*/
fd = open(file, O_RDONLY|O_BINARY);
if (fd < 0) {
Ns_Log(Warning, "fastpath: open(%s) failed: %s",
file, strerror(errno));
goto notfound;
}
#ifndef _WIN32
if (servPtr->fastpath.mmap) {
map = mmap(0, (size_t) stPtr->st_size, PROT_READ, MAP_SHARED,
fd, (off_t) 0);
if (map != MAP_FAILED) {
close(fd);
fd = -1;
result = Ns_ConnReturnData(conn, status, map, (int) stPtr->st_size, type);
munmap(map, (size_t) stPtr->st_size);
}
}
#endif
if (fd != -1) {
result = Ns_ConnReturnOpenFd(conn, status, type, fd,
(int) stPtr->st_size);
close(fd);
}
} else {
/*
* Search for an existing cache entry for this file, validating
* the contents against the current file mtime and size.
*/
#ifdef _WIN32
key = file;
#else
ukey.dev = stPtr->st_dev;
ukey.ino = stPtr->st_ino;
key = (char *) &ukey;
#endif
filePtr = NULL;
Ns_CacheLock(servPtr->fastpath.cache);
entPtr = Ns_CacheCreateEntry(servPtr->fastpath.cache, key, &new);
if (!new) {
while (entPtr != NULL &&
(filePtr = Ns_CacheGetValue(entPtr)) == NULL) {
Ns_CacheWait(servPtr->fastpath.cache);
entPtr = Ns_CacheFindEntry(servPtr->fastpath.cache, key);
}
if (filePtr != NULL &&
(filePtr->mtime != stPtr->st_mtime ||
filePtr->size != stPtr->st_size)) {
Ns_CacheUnsetValue(entPtr);
new = 1;
}
}
if (new) {
/*
* Read and cache new or invalidated entries in one big chunk.
*/
Ns_CacheUnlock(servPtr->fastpath.cache);
fd = open(file, O_RDONLY|O_BINARY);
if (fd < 0) {
filePtr = NULL;
Ns_Log(Warning, "fastpath: failed to open '%s': '%s'",
file, strerror(errno));
} else {
filePtr = ns_malloc(sizeof(File) + (size_t) stPtr->st_size);
filePtr->refcnt = 1;
filePtr->size = stPtr->st_size;
filePtr->mtime = stPtr->st_mtime;
nread = read(fd, filePtr->bytes, (size_t)filePtr->size);
close(fd);
if (nread != filePtr->size) {
Ns_Log(Warning, "fastpath: failed to read '%s': '%s'",
file, strerror(errno));
ns_free(filePtr);
filePtr = NULL;
}
}
Ns_CacheLock(servPtr->fastpath.cache);
entPtr = Ns_CacheCreateEntry(servPtr->fastpath.cache, key, &new);
if (filePtr != NULL) {
Ns_CacheSetValueSz(entPtr, filePtr, (size_t)filePtr->size);
} else {
Ns_CacheFlushEntry(entPtr);
}
Ns_CacheBroadcast(servPtr->fastpath.cache);
}
if (filePtr != NULL) {
++filePtr->refcnt;
Ns_CacheUnlock(servPtr->fastpath.cache);
result = Ns_ConnReturnData(conn, status, filePtr->bytes,
filePtr->size, type);
Ns_CacheLock(servPtr->fastpath.cache);
DecrEntry(filePtr);
}
Ns_CacheUnlock(servPtr->fastpath.cache);
if (filePtr == NULL) {
goto notfound;
}
}
return result;
notfound:
return Ns_ConnReturnNotFound(conn);
}
int
NsUrlToFile(Ns_DString *dsPtr, NsServer *servPtr, char *url)
{
int status;
if (servPtr->fastpath.url2file != NULL) {
status = (*servPtr->fastpath.url2file)(dsPtr, servPtr->server, url);
} else {
Ns_MakePath(dsPtr, servPtr->fastpath.pageroot, url, NULL);
status = NS_OK;
}
if (status == NS_OK) {
while (dsPtr->length > 0 && dsPtr->string[dsPtr->length-1] == '/') {
Ns_DStringTrunc(dsPtr, dsPtr->length-1);
}
}
return status;
}
|
Back to SourceForge.net Powered by ViewCVS 1.0-dev |