/* Handle a Retrieve request from a WWW client HTRetrieve.c ** =========================================== ** ** Authors ** CTB Carl Barker, Brunell ** DMX Daniel Martin ** TBL Tim Berners-Lee, CERN, Geneva timbl@info.cern.ch ** ** History: ** 29 Apr 91 (TBL) Split from daemon.c ** 5 Sept 91 (DMX) Added path simplification to prevent '..'ing to an ** uncorrect directory. ** Added '\r' as space for telneting to socket. ** 10 Sep 91 (TBL) Reject request and log if fails authorisation ** 26 Jan 92 (TBL) Added some of CTB's code for directory read. */ /* (c) CERN WorldWideWeb project 1990,91. See Copyright.html for details */ #define USE_PLAINTEXT /* Makes retrieval of postscript easier for now */ /* but not good sgml */ #define BUFFER_SIZE 4096 /* Arbitrary size for efficiency */ #define INFINITY 512 /* file name length @@ FIXME */ #include "HTUtils.h" #include "HTFormat.h" #include "tcp.h" #include "WWW.h" #ifdef RULES /* Use rules? */ #include "HTRules.h" #endif #include "HTParse.h" #ifdef unix #include "HTDirRead.h" #endif extern int WWW_TraceFlag; /* Control diagnostic output */ /*extern FILE * logfile; */ /* Log file output */ /* extern char HTClientHost[16]; */ /* Client name to be output */ extern int HTWriteASCII PARAMS((int soc, char * s)); /* In HTDaemon.c */ PUBLIC FILE * logfile = 0; /* Log file if any */ PUBLIC char *HTClientHost; /* Peer internet address */ #ifdef vms /* Convert unix-style name into VMS name ** ------------------------------------- ** ** Bug: Returns pointer to static -- non-reentrant ** This is a simplified version of vms_name in HTFile.c (local files only) */ PRIVATE char * vms_name (CONST char * fn) { /* We try converting the filename into Files-11 syntax. ** Here, we assume that the file is on our VMS node. ** Files-11, VMS, VAX and DECnet ** are trademarks of Digital Equipment Corporation. */ static char vmsname[INFINITY]; /* returned */ char * filename = (char*)malloc(strlen(fn)+1); /* Copy to hack */ char * second; /* 2nd slash */ char * last; /* last slash */ strcpy(filename, fn); second = strchr(filename+1, '/'); /* 2nd slash */ last = strrchr(filename, '/'); /* last slash */ if (!second) { /* Only one slash */ sprintf(vmsname, "%s", filename + 1); } else if(second==last) { /* Exactly two slashes */ *second = 0; /* Split filename from disk */ sprintf(vmsname, "%s:%s", filename+1, second+1); *second = '/'; /* restore */ } else { /* More than two slashes */ char * p; *second = 0; /* Split disk from directories */ *last = 0; /* Split dir from filename */ sprintf(vmsname, "%s:[%s]%s", filename+1, second+1, last+1); *second = *last = '/'; /* restore filename */ for (p=strchr(vmsname, '['); *p!=']'; p++) if (*p=='/') *p='.'; /* Convert dir sep. to dots */ } free(filename); return vmsname; } #endif /* vms */ /* Read a file ** ----------- ** ** The function copies a file given a source and destination file number. ** The destination may be a network socket. ** ** On exit, ** returns 0 for end of file, <0 for error. */ PRIVATE int read_file ARGS2( int, dest, int, source) { unsigned int status; char buffer[BUFFER_SIZE]; for(;;) { status = read(source, buffer, BUFFER_SIZE); if (!status) return 0; /* OK */ (void) NETWRITE(dest, buffer, status); } } /* Convert a Plain Text file ** ------------------------- ** ** The function copies a file given a source and destination file number. ** The destination may be a network socket. ** It translates the file from plain ASCII to an HTML ** preformatted section. ** ** On exit, ** returns 0 for end of file, <0 for error. */ PUBLIC int HTSendPreformatted ARGS2( int, dest, int, source) { unsigned int status; char buffer[BUFFER_SIZE]; char buffer2[BUFFER_SIZE*5];/* Largest possibly necessary */ HTWriteASCII(dest, "
\r\n");
for(;;) {
char * p, *q;
status = NETREAD(source, buffer, BUFFER_SIZE);
if (status <= 0) break; /* OK */
for (p=buffer, q=buffer2; p' :
case '<' :
case '&' :
*q++ = TOASCII('&');
*q++ = TOASCII('#');
*q++ = TOASCII('0')+(TOASCII(c)/10);
*q++ = TOASCII('0')+(TOASCII(c)%10);
*q++ = TOASCII(';');
break;
default : *q++ = TOASCII(c);
} /* switch c */
}
(void) NETWRITE(dest, buffer2, q - buffer2);
}
HTWriteASCII(dest, " \r\n");
return 0;
}
/* Determine file format from file name
** ------------------------------------
**
** Note: This function is also in the browser file HTFile.c
** If it gets complicated, it should be shared. (HTFile.c has a lot of
** other stuff in!)
*/
PRIVATE HTFormat HTFileFormat ARGS1 (CONST char *,filename)
{
CONST char * extension;
for (extension=filename+strlen(filename);
(extension>filename) &&
(*extension != '.') &&
(*extension!='/');
extension--) /* search */ ;
if (*extension == '.') {
return 0==strcmp(".html", extension) ? WWW_HTML
: 0==strcmp(".rtf", extension) ? WWW_RICHTEXT
: 0==strcmp(".txt", extension) ? WWW_PLAINTEXT
: 0==strcmp(".tar", extension) ? WWW_BINARY
: 0==strcmp(".hqx", extension) ? WWW_BINARY
: 0==strcmp(".Z", extension) ? WWW_BINARY
: WWW_PLAINTEXT; /* Unrecognised : try plain text */
} else {
return WWW_PLAINTEXT;
}
}
/* Retrieve a file
** ---------------
*/
#ifdef __STDC__
int HTRetrieve(const char * arg, const char * keywords, int soc)
#else
int HTRetrieve(arg, keywords, soc)
char *arg;
char *keywords;
int soc;
#endif
{
char * document_name; /* Pointer to filename or group list*/
int fd; /* File descriptor number */
int status; /* of file_read */
char * arg2 = 0; /* Simplified argument */
struct stat file_status;
if (keywords) {
if (TRACE) printf("HTHandle: can't perform search %s\n",
arg);
HTWriteASCII(soc,
"Sorry, this server does not perform searches.\n");
return fd;
}
StrAllocCopy(arg2, arg);
HTSimplify(arg2); /* Remove ".." etc (DMX) @@ No support for VMS syntax */
#ifdef RULES
{
char * arg3 = arg2;
arg2 = HTTranslate(arg3);
free(arg3);
}
if (!arg2) {
HTWriteASCII(soc,
"Document address invalid or access not authorised\n");
/* if (logfile) {
fprintf(logfile, "** SECURITY FAIL FOR ABOVE **\n");
fflush(logfile);
}
*/
if (TRACE) printf( "HTHandle: Security fail ***\n");
return fd;
}
#endif
/* Remove host part.
*/
document_name = HTParse (arg2, "", PARSE_PATH | PARSE_PUNCTUATION);
free(arg2);
if (*document_name) { /* (else return test message) */
HTFormat format = HTFileFormat(document_name);
char * filename = document_name; /* local name for file */
#ifdef vms
/* Assume that the file is in Unix-style syntax if it contains a '/'
after the leading one @@ */
filename = strchr(document_name + 1, '/') ?
vms_name(document_name) : document_name + 1;
#endif
/* What sort of a file is it?
*/
if (stat(filename,&file_status)!=0) {
HTWriteASCII(soc,"Sorry, server cannot read file status\r\n");
free(document_name);
return(-1); /* No socket open */
};
if (((file_status.st_mode) & S_IFMT) == S_IFDIR) {
/* if file is a directory */
#ifdef unix
DirToHTML(filename,soc,"0.9");
#else
HTWriteASCII(soc,
"Sorry, non-unix server not compiled to read directories\r\n");
#endif
free(document_name);
return (-1);
}
/* Open it as a file
*/
fd = open(filename, O_RDONLY, 0);
if(TRACE) printf ("HTAccess: Opening `%s' gives %d\n",
document_name, fd);
if (fd<0) {
if (TRACE) printf("HTHandle: can't open file %s\n",
filename);
HTWriteASCII(soc,
"Document address invalid or access not authorised\n");
free(document_name);
return fd;
}
/* Tell the client which format is to be sent */
if (format == WWW_HTML) {
status = read_file(soc, fd);
} else {
if (format==WWW_PLAINTEXT) {
#ifdef USE_PLAINTEXT
HTWriteASCII(soc, "