📄 http.c
字号:
*start=0;
*end=filesize-1;
if (*str=='-')
{
*start=filesize-strtol(str+1,&ss,10);
return ((ss!=str) && (!*ss));
};
*start=strtol(str,&ss,10);
if ((ss==str) || (*ss!='-'))
return FALSE;
str=ss+1;
if (!*str)
return TRUE;
*end=strtol(str,&ss,10);
if ((ss==str) || (*ss) || (*end<*start))
return FALSE;
return TRUE;
}
/*********************************************************************
** HTTP
*********************************************************************/
char *HTTPReasonByStatus(uint16 code)
{
static struct _HTTPReasons {
uint16 status;
char *reason;
} *r,reasons[] =
{
{ 100,"Continue" },
{ 101,"Switching Protocols" },
{ 200,"OK" },
{ 201,"Created" },
{ 202,"Accepted" },
{ 203,"Non-Authoritative Information" },
{ 204,"No Content" },
{ 205,"Reset Content" },
{ 206,"Partial Content" },
{ 300,"Multiple Choices" },
{ 301,"Moved Permanently" },
{ 302,"Moved Temporarily" },
{ 303,"See Other" },
{ 304,"Not Modified" },
{ 305,"Use Proxy" },
{ 400,"Bad Request" },
{ 401,"Unauthorized" },
{ 402,"Payment Required" },
{ 403,"Forbidden" },
{ 404,"Not Found" },
{ 405,"Method Not Allowed" },
{ 406,"Not Acceptable" },
{ 407,"Proxy Authentication Required" },
{ 408,"Request Timeout" },
{ 409,"Conflict" },
{ 410,"Gone" },
{ 411,"Length Required" },
{ 412,"Precondition Failed" },
{ 413,"Request Entity Too Large" },
{ 414,"Request-URI Too Long" },
{ 415,"Unsupported Media Type" },
{ 500,"Internal Server Error" },
{ 501,"Not Implemented" },
{ 502,"Bad Gateway" },
{ 503,"Service Unavailable" },
{ 504,"Gateway Timeout" },
{ 505,"HTTP Version Not Supported" },
{ 000, NULL }
};
r=reasons;
while (r->status<=code)
if (r->status==code)
return (r->reason);
else
r++;
return "No Reason";
}
int32 HTTPRead(TSession *s,char *buffer,uint32 len)
{
return 0;
}
abyss_bool HTTPWrite(TSession *s,char *buffer,uint32 len)
{
if (s->chunkedwrite && s->chunkedwritemode)
{
char t[16];
if (ConnWrite(s->conn,t,sprintf(t,"%x"CRLF,len)))
if (ConnWrite(s->conn,buffer,len))
return ConnWrite(s->conn,CRLF,2);
return FALSE;
}
return ConnWrite(s->conn,buffer,len);
}
abyss_bool HTTPWriteEnd(TSession *s)
{
if (!s->chunkedwritemode)
return TRUE;
if (s->chunkedwrite)
{
/* May be one day trailer dumping will be added */
s->chunkedwritemode=FALSE;
return ConnWrite(s->conn,"0"CRLF CRLF,5);
}
s->keepalive=FALSE;
return TRUE;
}
/*********************************************************************
** Response
*********************************************************************/
void ResponseError(TSession *r)
{
char *reason=HTTPReasonByStatus(r->status);
char z[500];
ResponseAddField(r,"Content-type","text/html");
ResponseWrite(r);
sprintf(z,"<HTML><HEAD><TITLE>Error %d</TITLE></HEAD>"
"<BODY><H1>Error %d</H1><P>%s</P>" SERVER_HTML_INFO
"</BODY></HTML>",
r->status,r->status,reason);
ConnWrite(r->conn,z,strlen(z));
}
abyss_bool ResponseChunked(TSession *r)
{
/* This is only a hope, things will be real only after a call of ResponseWrite */
r->chunkedwrite=(r->versionmajor>=1) && (r->versionminor>=1);
r->chunkedwritemode=TRUE;
return TRUE;
}
void ResponseStatus(TSession *r,uint16 code)
{
r->status=code;
}
void ResponseStatusErrno(TSession *r)
{
uint16 code;
switch (errno)
{
case EACCES:
code=403;
break;
case ENOENT:
code=404;
break;
default:
code=500;
};
ResponseStatus(r,code);
}
abyss_bool ResponseAddField(TSession *r,char *name,char *value)
{
return TableAdd(&r->response_headers,name,value);
}
void ResponseWrite(TSession *r)
{
abyss_bool connclose=TRUE;
char z[64];
TTableItem *ti;
uint16 i;
char *reason;
/* if status == 0 then this is an error */
if (r->status==0)
r->status=500;
/* the request was treated */
r->done=TRUE;
reason=HTTPReasonByStatus(r->status);
sprintf(z,"HTTP/1.1 %d ",r->status);
ConnWrite(r->conn,z,strlen(z));
ConnWrite(r->conn,reason,strlen(reason));
ConnWrite(r->conn,CRLF,2);
/* generation of the connection field */
if ((r->status<400) && (r->keepalive) && (r->cankeepalive))
connclose=FALSE;
ResponseAddField(r,"Connection",
(connclose?"close":"Keep-Alive"));
if (!connclose)
{
sprintf(z,"timeout=%lu, max=%lu",r->server->keepalivetimeout
,r->server->keepalivemaxconn);
ResponseAddField(r,"Keep-Alive",z);
if (r->chunkedwrite && r->chunkedwritemode)
{
if (!ResponseAddField(r,"Transfer-Encoding","chunked"))
{
r->chunkedwrite=FALSE;
r->keepalive=FALSE;
};
};
}
else
{
r->keepalive=FALSE;
r->chunkedwrite=FALSE;
};
/* generation of the date field */
if ((r->status>=200) && DateToString(&r->date,z))
ResponseAddField(r,"Date",z);
/* Generation of the server field */
if (r->server->advertise)
ResponseAddField(r,"Server",SERVER_HVERSION);
/* send all the fields */
for (i=0;i<r->response_headers.size;i++)
{
ti=&r->response_headers.item[i];
ConnWrite(r->conn,ti->name,strlen(ti->name));
ConnWrite(r->conn,": ",2);
ConnWrite(r->conn,ti->value,strlen(ti->value));
ConnWrite(r->conn,CRLF,2);
};
ConnWrite(r->conn,CRLF,2);
}
abyss_bool ResponseContentType(TSession *r,char *type)
{
return ResponseAddField(r,"Content-type",type);
}
abyss_bool ResponseContentLength(TSession *r,uint64 len)
{
char z[32];
sprintf(z,"%lu",len);
return ResponseAddField(r,"Content-length",z);
}
/*********************************************************************
** MIMEType
*********************************************************************/
TList _MIMETypes,_MIMEExt;
TPool _MIMEPool;
void MIMETypeInit()
{
ListInit(&_MIMETypes);
ListInit(&_MIMEExt);
PoolCreate(&_MIMEPool,1024);
}
abyss_bool MIMETypeAdd(char *type,char *ext)
{
uint16 index;
if (ListFindString(&_MIMETypes,type,&index))
type=_MIMETypes.item[index];
else
if (!(type=PoolStrdup(&_MIMEPool,type)))
return FALSE;
if (ListFindString(&_MIMEExt,ext,&index))
_MIMETypes.item[index]=type;
else
if (ext=PoolStrdup(&_MIMEPool,ext))
return (ListAdd(&_MIMETypes,type) && ListAdd(&_MIMEExt,ext));
else
return FALSE;
return TRUE;
}
char *MIMETypeFromExt(char *ext)
{
uint16 extindex;
if (!ListFindString(&_MIMEExt,ext,&extindex))
return NULL;
else
return _MIMETypes.item[extindex];
}
char *MIMETypeFromFileName(char *filename)
{
char *p=filename+strlen(filename),*z=NULL;
while ((*p!='.') && (p>=filename) && ((*p)!='/'))
p--;
if (*p=='.')
z=MIMETypeFromExt(p+1);
if (z)
return z;
else
return "application/octet-stream";
}
char *MIMETypeGuessFromFile(char *filename)
{
char *p=filename+strlen(filename),*z=NULL;
TFile file;
while ((*p!='.') && (p>=filename) && ((*p)!='/'))
p--;
if (*p=='.')
z=MIMETypeFromExt(p+1);
if (z)
return z;
if (FileOpen(&file,filename,O_BINARY | O_RDONLY))
{
uint8 buffer[80],c;
int32 len,i,n=0;
i=len=FileRead(&file,buffer,80);
while (i>0)
{
i--;
c=buffer[i];
if ((c>=' ') || (isspace(c)) || (c==26))
n++;
};
if (n==len)
z="text/plain";
FileClose(&file);
};
if (z)
return z;
else
return "application/octet-stream";
}
/*********************************************************************
** Date
*********************************************************************/
static char *_DateDay[7]=
{
"Sun","Mon","Tue","Wed","Thu","Fri","Sat"
};
static char *_DateMonth[12]=
{
"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
};
static int32 _DateTimeBias=0;
static char _DateTimeBiasStr[6]="";
abyss_bool DateToString(TDate *tm,char *s)
{
if (mktime(tm)==(time_t)(-1))
{
*s='\0';
return FALSE;
};
sprintf(s,"%s, %02d %s %04d %02d:%02d:%02d GMT",_DateDay[tm->tm_wday],tm->tm_mday,
_DateMonth[tm->tm_mon],tm->tm_year+1900,tm->tm_hour,tm->tm_min,tm->tm_sec);
return TRUE;
}
abyss_bool DateToLogString(TDate *tm,char *s)
{
time_t t;
TDate d;
if ((t=mktime(tm))!=(time_t)(-1))
if (DateFromLocal(&d,t))
{
sprintf(s,"%02d/%s/%04d:%02d:%02d:%02d %s",d.tm_mday,_DateMonth[d.tm_mon],
d.tm_year+1900,d.tm_hour,d.tm_min,d.tm_sec,_DateTimeBiasStr);
return TRUE;
};
*s='\0';
return FALSE;
}
abyss_bool DateDecode(char *s,TDate *tm)
{
uint32 n=0;
/* Ignore spaces, day name and spaces */
while ((*s==' ') || (*s=='\t'))
s++;
while ((*s!=' ') && (*s!='\t'))
s++;
while ((*s==' ') || (*s=='\t'))
s++;
/* try to recognize the date format */
if (sscanf(s,"%*s %d %d:%d:%d %d%*s",&tm->tm_mday,&tm->tm_hour,&tm->tm_min,
&tm->tm_sec,&tm->tm_year)!=5)
if (sscanf(s,"%d %n%*s %d %d:%d:%d GMT%*s",&tm->tm_mday,&n,&tm->tm_year,
&tm->tm_hour,&tm->tm_min,&tm->tm_sec)!=5)
if (sscanf(s,"%d-%n%*[A-Za-z]-%d %d:%d:%d GMT%*s",&tm->tm_mday,&n,&tm->tm_year,
&tm->tm_hour,&tm->tm_min,&tm->tm_sec)!=5)
return FALSE;
/* s points now to the month string */
s+=n;
for (n=0;n<12;n++)
{
char *p=_DateMonth[n];
if (tolower(*p++)==tolower(*s))
if (*p++==tolower(s[1]))
if (*p==tolower(s[2]))
break;
};
if (n==12)
return FALSE;
tm->tm_mon=n;
/* finish the work */
if (tm->tm_year>1900)
tm->tm_year-=1900;
else
if (tm->tm_year<70)
tm->tm_year+=100;
tm->tm_isdst=0;
return (mktime(tm)!=(time_t)(-1));
}
int32 DateCompare(TDate *d1,TDate *d2)
{
int32 x;
if ((x=d1->tm_year-d2->tm_year)==0)
if ((x=d1->tm_mon-d2->tm_mon)==0)
if ((x=d1->tm_mday-d2->tm_mday)==0)
if ((x=d1->tm_hour-d2->tm_hour)==0)
if ((x=d1->tm_min-d2->tm_min)==0)
x=d1->tm_sec-d2->tm_sec;
return x;
}
abyss_bool DateFromGMT(TDate *d,time_t t)
{
TDate *dx;
if (dx=gmtime(&t))
{
*d=*dx;
return TRUE;
};
return FALSE;
}
abyss_bool DateFromLocal(TDate *d,time_t t)
{
return DateFromGMT(d,t+_DateTimeBias*2);
}
abyss_bool DateInit()
{
time_t t;
TDate gmt,local,*d;
time(&t);
if (DateFromGMT(&gmt,t))
if (d=localtime(&t))
{
local=*d;
_DateTimeBias=(local.tm_sec-gmt.tm_sec)+(local.tm_min-gmt.tm_min)*60
+(local.tm_hour-gmt.tm_hour)*3600;
sprintf(_DateTimeBiasStr,"%+03d%02d",_DateTimeBias/3600,(_DateTimeBias % 3600)/60);
return TRUE;
};
return FALSE;
}
/*********************************************************************
** Base64
*********************************************************************/
void Base64Encode(char *s,char *d)
{
/* Conversion table. */
static char tbl[64] = {
'A','B','C','D','E','F','G','H',
'I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X',
'Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n',
'o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3',
'4','5','6','7','8','9','+','/'
};
uint32 i,length=strlen(s);
char *p=d;
/* Transform the 3x8 bits to 4x6 bits, as required by base64. */
for (i = 0; i < length; i += 3)
{
*p++ = tbl[s[0] >> 2];
*p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
*p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
*p++ = tbl[s[2] & 0x3f];
s += 3;
}
/* Pad the result if necessary... */
if (i == length + 1)
*(p - 1) = '=';
else if (i == length + 2)
*(p - 1) = *(p - 2) = '=';
/* ...and zero-terminate it. */
*p = '\0';
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -