#include "shrink.h" /************************************************************************ ** Function name: ncasecmp ** Descriptions: 判断两字符串在len长度范围内是否相等 ** input parameters: s1:字符串1 ** s2:字符串2 ** len:要比较的长度 ** Returned value: 0 相等 *************************************************************************/ int ncasecmp(const char *s1, const char *s2, size_t len) { const char *e = s1 + len - 1; int ret; for (; s1 < e && *s1 != '\0' && *s2 != '\0' && tolower(*s1) == tolower(*s2); s1++, s2++) ; ret = tolower(*s1) - tolower(*s2); return (ret); } /************************************************************************ ** Function name: server ** Descriptions: web服务主函数 ** output parameters: pr:服务请求指针 *************************************************************************/ void* server(void * pr) { #ifdef _ZLGIP size_t n; size_t left; #endif struct requestlist* prl = (struct requestlist *)pr; /* 获取请求结构 */ struct request *preq = &(prl->r); parse(preq,preq->io_remote.buf); /* 扫描请求行 */ #ifdef _WIN32 comm_write(preq->comm_remote,preq->io_local.buf,preq->io_local.readlen); #endif #ifdef _ZLGIP left = preq->io_local.readlen; n = 0; while(left!=0) { if (left > MAX_TCP_DATA) { n += comm_write(preq->comm_remote,preq->io_local.buf+n,MAX_TCP_DATA); left -= MAX_TCP_DATA; } else { comm_write(preq->comm_remote,preq->io_local.buf+n,left); break; } } #endif #ifdef _DEBUG printf("write\n%s",preq->io_local.buf); #endif clean(preq); prl->next = prlfree; prlfree = prl; return NULL; } /************************************************************************ ** Function name: clean ** Descriptions: 清理请求 ** output parameters: pr:服务请求指针 *************************************************************************/ void clean(struct request * pr) { comm_close(pr->comm_remote); if ((int)pr->fd > 0) { fs_close(pr->fd); } } /************************************************************************ ** Function name: errstatus ** Descriptions: 输出错误信息 ** input parameters: status:错误编号 ** descr:错误原因字符串 ** headers:原因头字符串 ** fmt:format ** ...:不定长输入 ** output parameters: pr:服务请求指针 *************************************************************************/ void errstatus(struct request *pr, int status, const char *descr,const char *headers, const char *fmt, ...) { va_list ap; char msg[1000]; int n; n = _snprintf(msg, sizeof(msg), "HTTP/1.1 %d %s\r\n%s%s\r\n%d ", status, descr, headers, headers[0] == '\0' ? "" : "\r\n", status); va_start(ap, fmt); n += _vsnprintf(msg + n, sizeof(msg) - n, fmt, ap); if (n > (int) sizeof(msg)) n = sizeof(msg); va_end(ap); (void) strncpy(pr->io_local.buf, msg, sizeof(pr->io_local.buf)); pr->io_local.readlen = n; pr->io_local.done ++; } /************************************************************************ ** Function name: parse ** Descriptions: 扫描请求行,主要获得uri,protocol,method ** input parameters: buf:待分析的字符串 ** output parameters: pr:服务请求指针 *************************************************************************/ void parse(struct request * pr, const char * buf) { const char *fmt = "%" STR2(METHOD_MAX) "s " "%" STR2(URI_MAX) "s " "%" STR2(METHOD_MAX) "s"; if (sscanf(buf, fmt, pr->method, pr->uri, pr->protocol) != 3) //获得method,uri,protocol { errstatus(pr, 404, "Bad Request","", "Bad Request"); } else if (pr->uri[0] != '/') //判断uri { errstatus(pr, 404, "Bad Request","", "Bad Request"); } else if (ncasecmp(pr->protocol,"HTTP",4) != 0) //判断protocol { errstatus(pr, 501, "Bad Protocol","", "Procotol Not Supported"); } else if (ncasecmp(pr->method,"GET",3) == 0) //GET方法 { pr->http_method = HTTP_GET; } else if (ncasecmp(pr->method,"POST",4) == 0) //POST方法 { pr->http_method = HTTP_POST; } if (pr->io_local.done == 0) { parsehead(pr, strchr(buf,'\n')+1); deal(pr); } } static int montoi(const char *s) { static const char *ar[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; int i; for (i = 0; i < (int) NELEMS(ar); i++) if (ncasecmp(s, ar[i],3) == 0) return (i); return (-1); } static time_t datetosec(const char *s) { struct tm tm; char mon[32]; int sec, min, hour, mday, month, year; (void) memset(&tm, 0, sizeof(tm)); tm.tm_isdst = 1; /* Daylight saving time is in effect */ sec = min = hour = mday = month = year = 0; if (((sscanf(s, "%d/%3s/%d %d:%d:%d", &mday, mon, &year, &hour, &min, &sec) == 6) || (sscanf(s, "%d %3s %d %d:%d:%d", &mday, mon, &year, &hour, &min, &sec) == 6) || (sscanf(s, "%*3s, %d %3s %d %d:%d:%d", &mday, mon, &year, &hour, &min, &sec) == 6) || (sscanf(s, "%d-%3s-%d %d:%d:%d", &mday, mon, &year, &hour, &min, &sec) == 6)) && (month = montoi(mon)) != -1) { tm.tm_mday = mday; tm.tm_mon = month; tm.tm_year = year; tm.tm_hour = hour; tm.tm_min = min; tm.tm_sec = sec; } if (tm.tm_year > 1900) tm.tm_year -= 1900; else if (tm.tm_year < 70) tm.tm_year += 100; return (mktime(&tm)); } /************************************************************************ ** Function name: parsehead ** Descriptions: 扫描请求头 ** input parameters: buf:待分析的字符串 ** output parameters: pr:服务请求指针 *************************************************************************/ void parsehead(struct request * pr, char * buf) { // char val[IO_MAX]; char *p; while (buf != NULL && buf[0] != '\n' && buf[0] != '\r') { if (ncasecmp(buf, "User-Agent: ", 12) == 0) { //c->useragent = mystrdup(fetch(s + 12, val,sizeof(val))); } else if (ncasecmp(buf, "Content-Type: ", 14) == 0) { //c->ctype = mystrdup(fetch(s + 14, val, sizeof(val))); } else if (ncasecmp(buf, "Content-Length: ", 16) == 0) { //c->clength = strtoul(fetch(s + 15,val, sizeof(val)), NULL, 10); p = &buf[16]; pr->plength = atoi(p); } else if (ncasecmp(buf, "If-Modified-Since: ", 19) == 0) { //c->ims = datetosec(fetch(s + 19, val, sizeof(val))); p = &buf[19]; pr->ims = datetosec(p); } else if (ncasecmp(buf, "Authorization: ", 15) == 0) { //c->auth = mystrdup(fetch(s + 15, val, sizeof(val))); } else if (ncasecmp(buf, "Referer: ", 9) == 0) { //c->referer = mystrdup(fetch(s + 9, val, sizeof(val))); } else if (ncasecmp(buf, "Cookie: ", 8) == 0) { //c->cookie = mystrdup(fetch(s + 8, val, sizeof(val))); } else if (ncasecmp(buf, "Location: ", 10) == 0) { //c->location = mystrdup(fetch(s + 10, val, sizeof(val))); } else if (ncasecmp(buf, "Status: ", 8) == 0) { //c->status = strtoul(fetch(s+8, val, sizeof(val)),0,10); } if ((buf = strchr(buf, '\n')) != NULL) //取得下一行 buf++; } if (pr->http_method == HTTP_POST) { if ((buf = strchr(buf, '\n')) != NULL) //取得下一行 buf++; if (buf != NULL && buf[0] != '\n' && buf[0] != '\r') { pr->message = buf; //获得message } } }