📄 server.c
字号:
/*******************************************************************************
**
** server.c
**
** This file is part of the ABYSS Web server project.
**
** Copyright (C) 2000 by Moez Mahfoudh <mmoez@bigfoot.com>.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
**
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef ABYSS_WIN32
#include <io.h>
#else
/* Check this
#include <sys/io.h>
*/
#endif /* ABYSS_WIN32 */
#include <fcntl.h>
#include "abyss.h"
#define BOUNDARY "##123456789###BOUNDARY"
typedef int (*TQSortProc)(const void *, const void *);
int cmpfilenames(const TFileInfo **f1,const TFileInfo **f2)
{
if (((*f1)->attrib & A_SUBDIR) && !((*f2)->attrib & A_SUBDIR))
return (-1);
if (!((*f1)->attrib & A_SUBDIR) && ((*f2)->attrib & A_SUBDIR))
return 1;
return strcmp((*f1)->name,(*f2)->name);
}
int cmpfiledates(const TFileInfo **f1,const TFileInfo **f2)
{
if (((*f1)->attrib & A_SUBDIR) && !((*f2)->attrib & A_SUBDIR))
return (-1);
if (!((*f1)->attrib & A_SUBDIR) && ((*f2)->attrib & A_SUBDIR))
return 1;
return ((*f1)->time_write-(*f2)->time_write);
}
abyss_bool ServerDirectoryHandler(TSession *r,char *z,TDate *dirdate)
{
TFileInfo fileinfo,*fi;
TFileFind findhandle;
char *p,z1[26],z2[20],z3[9],u,*z4;
TList list;
int16 i;
uint32 k;
abyss_bool text=FALSE;
abyss_bool ascending=TRUE;
uint16 sort=1; /* 1=by name, 2=by date */
struct tm ftm;
TPool pool;
TDate date;
if (r->query)
if (strcmp(r->query,"plain")==0)
text=TRUE;
else if (strcmp(r->query,"name-up")==0)
{
sort=1;
ascending=TRUE;
}
else if (strcmp(r->query,"name-down")==0)
{
sort=1;
ascending=FALSE;
}
else if (strcmp(r->query,"date-up")==0)
{
sort=2;
ascending=TRUE;
}
else if (strcmp(r->query,"date-down")==0)
{
sort=2;
ascending=FALSE;
}
else
{
ResponseStatus(r,400);
return TRUE;
};
if (DateCompare(&r->date,dirdate)<0)
dirdate=&r->date;
if (p=RequestHeaderValue(r,"If-Modified-Since"))
if (DateDecode(p,&date))
if (DateCompare(dirdate,&date)<=0)
{
ResponseStatus(r,304);
ResponseWrite(r);
return TRUE;
};
if (!FileFindFirst(&findhandle,z,&fileinfo))
{
ResponseStatusErrno(r);
return TRUE;
};
ListInit(&list);
if (!PoolCreate(&pool,1024))
{
ResponseStatus(r,500);
return TRUE;
};
do
{
/* Files which names start with a dot are ignored */
/* This includes implicitly the ./ and ../ */
if (*fileinfo.name=='.')
if (strcmp(fileinfo.name,"..")==0)
{
if (strcmp(r->uri,"/")==0)
continue;
}
else
continue;
if (fi=(TFileInfo *)PoolAlloc(&pool,sizeof(fileinfo)))
{
memcpy(fi,&fileinfo,sizeof(fileinfo));
if (ListAdd(&list,fi))
continue;
};
ResponseStatus(r,500);
FileFindClose(&findhandle);
ListFree(&list);
PoolFree(&pool);
return TRUE;
} while (FileFindNext(&findhandle,&fileinfo));
FileFindClose(&findhandle);
/* Send something to the user to show that we are still alive */
ResponseStatus(r,200);
ResponseContentType(r,(text?"text/plain":"text/html"));
if (DateToString(dirdate,z))
ResponseAddField(r,"Last-Modified",z);
ResponseChunked(r);
ResponseWrite(r);
if (r->method!=m_head)
{
if (text)
{
sprintf(z,"Index of %s" CRLF,r->uri);
i=strlen(z)-2;
p=z+i+2;
while (i>0)
{
*(p++)='-';
i--;
};
*p='\0';
strcat(z,CRLF CRLF
"Name Size Date-Time Type" CRLF
"--------------------------------------------------------------------------------"CRLF);
}
else
{
sprintf(z,"<HTML><HEAD><TITLE>Index of %s</TITLE></HEAD><BODY>"
"<H1>Index of %s</H1><PRE>",r->uri,r->uri);
strcat(z,"Name Size Date-Time Type<HR WIDTH=100%>"CRLF);
};
HTTPWrite(r,z,strlen(z));
/* Sort the files */
qsort(list.item,list.size,sizeof(void *),(TQSortProc)(sort==1?cmpfilenames:cmpfiledates));
/* Write the listing */
if (ascending)
i=0;
else
i=list.size-1;
while ((i<list.size) && (i>=0))
{
fi=list.item[i];
if (ascending)
i++;
else
i--;
strcpy(z,fi->name);
k=strlen(z);
if (fi->attrib & A_SUBDIR)
{
z[k++]='/';
z[k]='\0';
};
if (k>24)
{
z[10]='\0';
strcpy(z1,z);
strcat(z1,"...");
strcat(z1,z+k-11);
k=24;
p=z1+24;
}
else
{
strcpy(z1,z);
k++;
p=z1+k;
while (k<25)
z1[k++]=' ';
z1[25]='\0';
};
ftm=*(gmtime(&fi->time_write));
sprintf(z2,"%02u/%02u/%04u %02u:%02u:%02u",ftm.tm_mday,ftm.tm_mon,
ftm.tm_year+1900,ftm.tm_hour,ftm.tm_min,ftm.tm_sec);
if (fi->attrib & A_SUBDIR)
{
strcpy(z3," -- ");
z4="Directory";
}
else
{
if (fi->size<9999)
u='b';
else
{
fi->size/=1024;
if (fi->size<9999)
u='K';
else
{
fi->size/=1024;
if (fi->size<9999)
u='M';
else
u='G';
};
};
sprintf(z3,"%5lu %c",fi->size,u);
if (strcmp(fi->name,"..")==0)
z4="";
else
z4=MIMETypeFromFileName(fi->name);
if (!z4)
z4="Unknown";
};
if (text)
sprintf(z,"%s%s %s %s %s"CRLF,
z1,p,z3,z2,z4);
else
sprintf(z,"<A HREF=\"%s%s\">%s</A>%s %s %s %s"CRLF,
fi->name,(fi->attrib & A_SUBDIR?"/":""),z1,p,z3,z2,z4);
HTTPWrite(r,z,strlen(z));
};
/* Write the tail of the file */
if (text)
strcpy(z,SERVER_PLAIN_INFO);
else
strcpy(z,"</PRE>" SERVER_HTML_INFO "</BODY></HTML>" CRLF CRLF);
HTTPWrite(r,z,strlen(z));
};
HTTPWriteEnd(r);
/* Free memory and exit */
ListFree(&list);
PoolFree(&pool);
return TRUE;
}
abyss_bool ServerFileHandler(TSession *r,char *z,TDate *filedate)
{
char *mediatype;
TFile file;
uint64 filesize,start,end;
uint16 i;
TDate date;
char *p;
mediatype=MIMETypeGuessFromFile(z);
if (!FileOpen(&file,z,O_BINARY | O_RDONLY))
{
ResponseStatusErrno(r);
return TRUE;
};
if (DateCompare(&r->date,filedate)<0)
filedate=&r->date;
if (p=RequestHeaderValue(r,"if-modified-since"))
if (DateDecode(p,&date))
if (DateCompare(filedate,&date)<=0)
{
ResponseStatus(r,304);
ResponseWrite(r);
return TRUE;
}
else
r->ranges.size=0;
filesize=FileSize(&file);
switch (r->ranges.size)
{
case 0:
ResponseStatus(r,200);
break;
case 1:
if (!RangeDecode((char *)(r->ranges.item[0]),filesize,&start,&end))
{
ListFree(&(r->ranges));
ResponseStatus(r,200);
break;
}
sprintf(z,"bytes %ld-%ld/%ld",start,end,filesize);
ResponseAddField(r,"Content-range",z);
ResponseContentLength(r,end-start+1);
ResponseStatus(r,206);
break;
default:
ResponseContentType(r,"multipart/ranges; boundary=" BOUNDARY);
ResponseStatus(r,206);
break;
};
if (r->ranges.size==0)
{
ResponseContentLength(r,filesize);
ResponseContentType(r,mediatype);
};
if (DateToString(filedate,z))
ResponseAddField(r,"Last-Modified",z);
ResponseWrite(r);
if (r->method!=m_head)
{
if (r->ranges.size==0)
ConnWriteFromFile(r->conn,&file,0,filesize-1,z,4096,0);
else if (r->ranges.size==1)
ConnWriteFromFile(r->conn,&file,start,end,z,4096,0);
else
for (i=0;i<=r->ranges.size;i++)
{
ConnWrite(r->conn,"--",2);
ConnWrite(r->conn,BOUNDARY,strlen(BOUNDARY));
ConnWrite(r->conn,CRLF,2);
if (i<r->ranges.size)
if (RangeDecode((char *)(r->ranges.item[i]),filesize,&start,&end))
{
/* Entity header, not response header */
sprintf(z,"Content-type: %s" CRLF
"Content-range: bytes %ld-%ld/%ld" CRLF
"Content-length: %lu" CRLF
CRLF,mediatype,start,end,filesize,end-start+1);
ConnWrite(r->conn,z,strlen(z));
ConnWriteFromFile(r->conn,&file,start,end,z,4096,0);
};
};
};
FileClose(&file);
return TRUE;
}
abyss_bool ServerDefaultHandlerFunc(TSession *r)
{
char *p,z[4096];
TFileStat fs;
uint16 i;
abyss_bool endingslash=FALSE;
TDate objdate;
if (!RequestValidURIPath(r))
{
ResponseStatus(r,400);
return TRUE;
};
/* Must check for * (asterisk uri) in the future */
if (r->method==m_options)
{
ResponseAddField(r,"Allow","GET, HEAD");
ResponseContentLength(r,0);
ResponseStatus(r,200);
return TRUE;
};
if ((r->method!=m_get) && (r->method!=m_head))
{
ResponseAddField(r,"Allow","GET, HEAD");
ResponseStatus(r,405);
return TRUE;
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -