home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1999 March B
/
SCO_CASTOR4RRT.iso
/
nsfast
/
root.9
/
usr
/
ns-home
/
nsapi
/
examples
/
service.c
/
service
Wrap
Text File
|
1998-08-19
|
9KB
|
309 lines
/*
* Copyright (c) 1994, 1995, 1996. Netscape Communications Corporation.
* All rights reserved.
*
* Use of this software is governed by the terms of the license agreement
* for the Netscape Enterprise or Netscape Personal Server between the
* parties.
*
*/
/* ------------------------------------------------------------------------ */
/*
* service.c: Example NSAPI functions to complete responses to requests
*
* The Server Application Functions in this file are Service class
* functions, and designed to demonstrate in general how to finish the
* server's response to a request.
*
* Rob McCool
*/
/*
The following three are standard headers for SAFs. They're used to
get the data structures and prototypes needed to declare and use SAFs.
*/
#include "base/pblock.h"
#include "base/session.h"
#include "frame/req.h"
#if defined(SENDV) /* for UnixWare (Gemini release) */
#include <sys/types.h>
#include <sys/sendv.h>
#endif
/* ----------------------------- send-images ------------------------------ */
/*
Users of Netscape 1.1 may be familiar with what those wacky client
guys are calling the "server push" version of dynamic document
refresh. One problem with doing this operation through CGI is that
it causes two processes, your CGI program and its corresponding
server process, to run. This can be wasteful. Further, your program
does not have direct access to the client socket and thus can't be
absolutely sure of when the client aborts a connection.
This service class function is a replacement for the doit.cgi
demonstration available on the Netscape home pages. When accessed
as /dir1/dir2/foo.picgroup, the function will check if it's being
accessed by Mozilla/1.1. If not, it will send a short error
message.
foo.picgroup should be a simple file which lists on every line a
filename followed by a content-type. The filenames will be filtered
such that they may only refer to files in the current directory.
Example .picgroup file:
one.gif image/gif
two.jpg image/jpeg
three.gif image/gif
Usage:
At the beginning of obj.conf:
Init fn=load-modules shlib=example.<ext> funcs=send-images
In mime.types:
type=magnus-internal/picgroup exts=picgroup
Inside an object in obj.conf:
Service method=(GET|HEAD) type=magnus-internal/picgroup fn=send-images
<ext> = so on UNIX
<ext> = dll on NT.
send-images also takes an optional parameter, delay, which specifies
the number of seconds to pause between images.
*/
#include "base/util.h" /* is_mozilla, getline */
#include "frame/protocol.h" /* protocol_start_response */
#include "base/file.h" /* system_fopenRO */
#include "base/buffer.h" /* filebuf */
#include "frame/log.h" /* log_error */
#include <stdio.h>
#ifndef XP_WIN32
#include <unistd.h> /* sleep */
#define NSAPI_PUBLIC
#else /* XP_WIN32 */
#include <windows.h>
#define NSAPI_PUBLIC __declspec(dllexport)
#endif /* XP_WIN32 */
#define PICGROUP_MAXLINE 300
#define DEFAULT_DELAY 1
#define FIRSTMSG "--AnUnlikelyOccurrence\n"
#define NEWMSG "\n--AnUnlikelyOccurrence\n"
#define MULTICT "multipart/x-mixed-replace; boundary=AnUnlikelyOccurrence"
#define ERRMSG \
"This feature requires <a href=\"ftp://ftp.netscape.com\">Netscape 1.1</a><p>"
/*
This function sends the given file to Netscape
*/
NSAPI_PUBLIC int _picgroup_send_file(char *dir, char *fn, char *ct, int delay,
Session *sn, Request *rq)
{
struct stat finfo;
filebuf *buf;
SYS_FILE fd;
int len, ret = REQ_PROCEED;
char ctbuf[PICGROUP_MAXLINE + sizeof("Content-type: ") + 2 + 1];
char *pathname = (char *) MALLOC(strlen(dir) + strlen(fn) + 1);
#if defined(SENDV) /* for UnixWare (Gemini release) */
struct sendv_iovec iosv[3];
#endif
util_sprintf(pathname, "%s%s", dir, fn);
/* If any errors, just skip it. The gotos are mostly for convenience. */
if(stat(pathname, &finfo) == -1)
goto done;
fd = system_fopenRO(pathname);
if(fd == SYS_ERROR_FD)
goto done;
#if defined(SENDV) /* for UnixWare (Gemini release) */
len = util_sprintf(ctbuf, "Content-type: %s\nContent-length: %d\n\n",
ct, finfo.st_size);
iosv[0].sendv_flags = 0;
iosv[0].sendv_base = ctbuf;
iosv[0].sendv_len = len;
iosv[1].sendv_flags = SENDV_FD;
iosv[1].sendv_fd = fd;
iosv[1].sendv_off = 0;
iosv[1].sendv_len = finfo.st_size;
iosv[2].sendv_flags = 0;
iosv[2].sendv_base = NEWMSG;
iosv[2].sendv_len = strlen(NEWMSG);
if (net_sendv(sn->csd, iosv, 3) == IO_ERROR)
ret = REQ_EXIT;
#else /* !SENDV */
buf = filebuf_open_nostat(fd, FILE_BUFFERSIZE, &finfo);
if(!buf) {
system_fclose(fd);
goto done;
}
len = util_sprintf(ctbuf, "Content-type: %s\nContent-length: %d\n\n",
ct, finfo.st_size);
if(net_write(sn->csd, ctbuf, len) == IO_ERROR)
ret = REQ_EXIT;
if(filebuf_buf2sd(buf, sn->csd) == IO_ERROR)
ret = REQ_EXIT;
filebuf_close(buf);
if(net_write(sn->csd, NEWMSG, strlen(NEWMSG)) == IO_ERROR)
ret = REQ_EXIT;
#endif /* !SENDV */
/* Pause to display */
#ifdef XP_WIN32
Sleep(delay*1000);
#else /* !XP_WIN32 */
sleep(delay);
#endif /* !XP_WIN32 */
done:
FREE(pathname);
return ret;
}
NSAPI_PUBLIC int send_images(pblock *pb, Session *sn, Request *rq)
{
char *delaystr = pblock_findval("delay", pb);
/* Server variables */
char *path = pblock_findval("path", rq->vars);
/* Work variables */
filebuf *groupbuf;
SYS_FILE fd;
char *ua, *t, *base;
char line[PICGROUP_MAXLINE], *ct;
struct stat *fi;
int lnum, ret, delay;
delay = (delaystr ? atoi(delaystr) : DEFAULT_DELAY);
/* We need to get rid of the internal content type. */
param_free(pblock_remove("content-type", rq->srvhdrs));
/*
There's a chance somebody accidentally sent us path info.
If they did, send not found.
*/
if( (t = pblock_findval("path-info", rq->vars)) ) {
protocol_status(sn, rq, PROTOCOL_NOT_FOUND, NULL);
log_error(LOG_WARN, "send-images", sn, rq, "%s%s not found", path, t);
return REQ_ABORTED;
}
/*
Get the file's cached stat information, and open it.
Errors mean it doesn't exist, or it can't be read
*/
if( (!(fi = request_stat_path(path, rq)) ) ||
( (fd = system_fopenRO(path)) == IO_ERROR) )
{
protocol_status(sn, rq, (file_notfound() ? PROTOCOL_NOT_FOUND :
PROTOCOL_FORBIDDEN), NULL);
log_error(LOG_WARN, "send-images", sn, rq, "error opening %s (%s)",
path, system_errmsg(0));
return REQ_ABORTED;
}
/* Use server native buffered I/O on the file */
groupbuf = filebuf_open_nostat(fd, FILE_BUFFERSIZE, fi);
if(!groupbuf) {
protocol_status(sn, rq, PROTOCOL_FORBIDDEN, NULL);
log_error(LOG_WARN,"send-file", sn, rq,
"error opening buffer from %s (%s)", path,
system_errmsg(fd));
system_fclose(fd);
return REQ_ABORTED;
}
protocol_status(sn, rq, PROTOCOL_OK, NULL);
/* Every time I have to check this variable I cringe. How revolting. */
if(request_header("user-agent", &ua, sn, rq) == REQ_ABORTED)
return REQ_ABORTED;
/* Check for Mozilla 1.1 or better */
if(!util_is_mozilla(ua, "1", "1")) {
/* Return a short error message */
pblock_nvinsert("content-type", "text/html", rq->srvhdrs);
if(protocol_start_response(sn, rq) != REQ_NOACTION)
(void) net_write(sn->csd, ERRMSG, strlen(ERRMSG));
return REQ_PROCEED;
}
/*
Normally, a call to stat followed by protocol_set_finfo would
be used here to handle conditional GET requests from the
browser. However, caching is not used for dynamic documents.
*/
/* Set content-type and begin response */
/* Technically, I should generate a random string here. */
pblock_nvinsert("content-type", MULTICT, rq->srvhdrs);
/* A noaction response from this function means the request was HEAD */
if(protocol_start_response(sn, rq) == REQ_NOACTION) {
filebuf_close(groupbuf); /* this also closes fd */
return REQ_PROCEED;
}
/* Start response by giving boundary string */
if(net_write(sn->csd, FIRSTMSG, strlen(FIRSTMSG)) == IO_ERROR)
return REQ_EXIT;
/* Get the base directory name */
base = STRDUP(path);
t = strrchr(base, FILE_PATHSEP);
*(t + 1) = '\0';
for(ret = 0, lnum = 1; ret == 0; ++lnum) {
ret = util_getline(groupbuf, lnum, PICGROUP_MAXLINE, line);
if(ret != -1) {
/* If no space, invalid format. But just skip. */
if(!(ct = strchr(line, ' ')))
continue;
*ct++ = '\0';
/* Only files in this directory are allowed. */
if(strchr(line, FILE_PATHSEP))
continue;
/* Send a page break followed by the image */
if(_picgroup_send_file(base, line, ct, delay, sn, rq) == REQ_EXIT)
ret = -1;
/* Check for EOF */
if(ret == 1)
ret = -1;
}
}
filebuf_close(groupbuf);
return REQ_PROCEED;
}