http.c
来自「一个vxworks下http任务socket层的实现代码」· C语言 代码 · 共 850 行 · 第 1/2 页
C
850 行
return ERROR;
}
// 分析得到HTTP的头部,分析完成后,可以获知第个句子的开始位置和长度,句子中每个单词的开始位置和长度。
// 典型的HTTP头部如下所示。
// GET /Loginstyle.css HTTP/1.1
// Accept: */*
// Referer: http://172.16.0.3
// Accept-Language: zh-cn
// Accept-Encoding: gzip, deflate
// User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
// Host: 172.16.0.3
// Connection: Keep-Alive
void getHttpHead(char * buf, int len)
{
int i, j;
short sentenceNo, wordNo;
BOOL sentenceStart, wordStart;
sentenceStart = FALSE;
wordStart = FALSE;
for (i = 0; i < len; i++)
{
sentenceNo = httpCtrlInfo.httpHeadDes.sentenceNum;
wordNo = httpCtrlInfo.httpHeadDes.sentence[sentenceNo].wordNum;
if (sentenceNo >= HTTP_HEAD_MAX_SENTENCE || wordNo >= HTTP_HEAD_MAX_WORD)
{
lpt(PT_WARN, " word or sentence is full \n");
return;
}
if ((buf[i] == ' ') || (buf[i] == '\r'))
{
// 单词结束
if (!wordStart)
{
continue;
}
// 计算一下单词长度
httpCtrlInfo.httpHeadDes.sentence[sentenceNo].word[wordNo].wordLen =
i - httpCtrlInfo.httpHeadDes.sentence[sentenceNo].word[wordNo].wordPtr;
httpCtrlInfo.httpHeadDes.sentence[sentenceNo].wordNum++;
wordStart = FALSE;
}
else if (buf[i] == '\n')
{
// 句子结束
if (!sentenceStart)
{
// 句子还未开始就结束了,说明是一个空行,HTTP头部分析结束。
return;
}
// 计算一下句子长度
httpCtrlInfo.httpHeadDes.sentence[sentenceNo].sentenceLen =
i - httpCtrlInfo.httpHeadDes.sentence[sentenceNo].sentencePtr;
httpCtrlInfo.httpHeadDes.sentenceNum++;
sentenceStart = FALSE;
}
else
{
if (!sentenceStart)
{
httpCtrlInfo.httpHeadDes.sentence[sentenceNo].sentencePtr = i;
sentenceStart = TRUE;
}
if (!wordStart)
{
httpCtrlInfo.httpHeadDes.sentence[sentenceNo].word[wordNo].wordPtr = i;
wordStart = TRUE;
}
}
}
}
void sendHttpFile(UINT8 * lpFileName)
{
int index =0;
FILE * fp;
char fileName[50];
memset(fileName, 0 , sizeof(fileName));
strcpy(fileName, lpFileName);
index = getHttpFile(fileName);
if (index >= 0)
{
// 发送的网页是由程序创建的。
char * fileBuf;
if(httpFileTable.files[index].createHtmlPage==NULL)
{
lpt(PT_WARN, "createHtmlPage is NULL \n");
httpSndState(HTTP_STATUS_SERVERERROR);
return ;
}
fileBuf = 0;
fileBuf = malloc(MAX_HTTP_FILE_LEN+1);
if (fileBuf == 0)
{
lpt(PT_ERROR,"can not malloc 64K mem \n");
httpSndState(HTTP_STATUS_SERVERERROR);
return ;
}
memset(fileBuf, 0, MAX_HTTP_FILE_LEN);
// 根据索引得到对应的生成HTML网页的回调函数,生成网页
if(httpFileTable.files[index].createHtmlPage(fileBuf, MAX_HTTP_FILE_LEN) != TRUE)
{
lpt(PT_ERROR,"createHtmlPage return error\n");
//httpSndState(HTTP_STATUS_NOTFOUND);
httpSndNotFindFile();
}
else
{
httpSndState(HTTP_STATUS_OK);
httpSndFileHead(fileName);
httpSndContent(fileBuf, strlen(fileBuf));
}
free(fileBuf);
return;
}
// 下面发送的文件都是存在FLASH上的。
if ((strncmp(fileName, "db.xml", 6) != 0) &&
(strstr(fileName,".ios")==NULL) &&
(strstr(fileName,".log")==NULL) &&
(strstr(fileName,".sys")==NULL) )
{
UINT8 tempString[50];
strcpy(tempString, "web/");
strcat(tempString, fileName);
strcpy(fileName, tempString);
}
// Open the file for reading
fp = fopen(fileName, "rb");
if (fp == NULL)
{
lpt1(PT_WARN,"sendHttpFile %s can not find\n",fileName);
//httpSndState(HTTP_STATUS_NOTFOUND);
httpSndNotFindFile();
return;
}
httpSndState(HTTP_STATUS_OK);
httpSndFileHead(fileName);
// 将FLASH上的文件内容提要发出去。
{
UINT8 buf[1024 + 1];
int uBytes;
// 将文件指针移到文件头
fseek(fp, 0, SEEK_SET);
for (;;)
{
// Read a buffer full from the file
memset(buf, 0, sizeof(buf));
uBytes = fread(buf, 1, 1024, fp);
if (uBytes > 0)
{
// 将读到的内容(地址为buf,长度为uBytes)发出去。
httpSndContent(buf, uBytes);
}
else
{
break;
}
}
}
fclose(fp);
}
/* 解析HTTP数据 */
// put方法是上传文件,以后考虑*/
int getHttpDataLen()
{
int i,j,contentLen;
char contentData[100];
memset(contentData,0,sizeof(contentData));
for(i=0;i<httpCtrlInfo.httpHeadDes.sentenceNum;i++)
{
for(j=0;j<httpCtrlInfo.httpHeadDes.sentence[i].wordNum;i++)
{
if(memcmp("Content-Length:",httpCtrlInfo.rcvBuf+httpCtrlInfo.httpHeadDes.sentence[i].word[j].wordPtr,
httpCtrlInfo.httpHeadDes.sentence[i].word[j].wordLen)==0)
{
memcpy(contentData,httpCtrlInfo.rcvBuf+httpCtrlInfo.httpHeadDes.sentence[i].word[j+1].wordPtr,
httpCtrlInfo.httpHeadDes.sentence[i].word[j+1].wordLen);
contentLen=atoi(contentData);
return contentLen;
}
}
}
return 0;
}
/*
http的数据分析
返回: 0--------成功
-1-------失败
>0-------应该收到的字节数
*/
int httpParse(void)
{
char fileName[50];
char methodString[50];
UINT8 method;
int index;
int dataLen, sentenceNum;
char * dataPtr;
// 解析HTTP头部,将头部的各个句子和单词分析出来,以便于分析。
getHttpHead(httpCtrlInfo.rcvBuf, strlen(httpCtrlInfo.rcvBuf));
// 对于代理服务器来说,数据和头部是分部发送的,所以还要收数据
// 得到应该有的HTML内容长度。
dataLen=getHttpDataLen();
sentenceNum = httpCtrlInfo.httpHeadDes.sentenceNum;
dataPtr = httpCtrlInfo.rcvBuf
+ httpCtrlInfo.httpHeadDes.sentence[sentenceNum-1].sentencePtr
+ httpCtrlInfo.httpHeadDes.sentence[sentenceNum-1].sentenceLen +3;
if (strlen(dataPtr) < dataLen)
{
// 得到HTML内容的实际长度小于应该有的长度,还未收齐,再收一次。
return dataLen;
}
// 第一句的第一个单词为METHOD。
memset(methodString, 0, sizeof(methodString));
memcpy(methodString, httpCtrlInfo.rcvBuf+httpCtrlInfo.httpHeadDes.sentence[0].word[0].wordPtr,
httpCtrlInfo.httpHeadDes.sentence[0].word[0].wordLen);
// 第一句的第二个单词为文件名,(如果是POST操作,可以理解为ACTION)
memset(fileName, 0, sizeof(fileName));
if (httpCtrlInfo.httpHeadDes.sentence[0].word[1].wordLen <= 1)
{
// 文件名为空,缺省为"login.htm"
strcpy(fileName, "login.htm");
}
else
{
memcpy(fileName, httpCtrlInfo.rcvBuf+httpCtrlInfo.httpHeadDes.sentence[0].word[1].wordPtr+1,
httpCtrlInfo.httpHeadDes.sentence[0].word[1].wordLen-1);
}
if (strcmp(methodString, "GET") == 0)
{
sendHttpFile(fileName);
}
else if (strcmp(methodString, "POST") == 0)
{
index = getHttpAction(fileName);
if (index < 0)
{
//httpSndState(HTTP_STATUS_NOTFOUND);
httpSndNotFindFile();
lpt(PT_WARN, "POST 文件找不到\n");
return -1;
}
if(actionTable.actions[index].onPostFunction != NULL)
{
char * pageBuf;
pageBuf = 0;
pageBuf = malloc(MAX_HTTP_FILE_LEN+1);
if (pageBuf == 0)
{
lpt(PT_ERROR,"can not malloc 64K mem \n");
httpSndState(HTTP_STATUS_SERVERERROR);
return -1;
}
/*
在action失败的情况下,pageBuf为空,会重复请求
*/
if(actionTable.actions[index].onPostFunction(dataPtr, strlen(dataPtr), pageBuf, MAX_HTTP_FILE_LEN)!=TRUE)
{
httpSndNotFindFile();
free(pageBuf);
return -1;
}
httpSndState(HTTP_STATUS_OK);
httpSndFileHead(fileName);
httpSndContent(pageBuf, strlen(pageBuf));
free(pageBuf);
}
}
else
{
httpSndState(HTTP_STATUS_NOTIMPLEMENTED);
lpt1(PT_WARN,"http Request method illeagal buf:\n%s\n", httpCtrlInfo.rcvBuf);
return -1;
}
return 0;
}
extern void htmlAddFileToHttp(void);
void taskHttp(void)
{
int sock, listenSocket;
struct sockaddr clientAddr;
int len, i;
//初始化HTTP表格
initHttpFileTable();
initActionTable();
// 安装HTML回调函数
htmlAddFileToHttp( );
listenSocket = httpServListen( );
for(;;)
{
len = sizeof(clientAddr);
sock = accept(listenSocket, &clientAddr, &len);
if (sock <= 0)
{
printf("Error in onAccept(), accept error!\n");
taskDelay(60);
continue;
}
// 将连接的SOCKET设置为非阻塞
{
long on;
on = TRUE;
ioctl(sock, FIONBIO, (int)&on);
}
memset((char *)&httpCtrlInfo, 0, sizeof(httpCtrlInfo));
httpCtrlInfo.connectSock = sock;
for (i = 0; i < 10; i++) // 最多收10次
{
len = recv(sock, httpCtrlInfo.rcvBuf, RCV_BUF_SIZE, 0);
if (len <= 0)
{
// 如果没有收到数据包,则延迟一段时间再收,次数越多,延迟时间越长。
taskDelay(i*10+1);
continue;
}
else
{
// 客户端发过来的数据都很少,一次都能收完,所以收到一个包就可以了。
// 如果客户端发过来的数据很多,则在接收成功后,需再查询一下,还有没有包。
// 这种情况暂时不存在,无需考虑。下面这行是检查SOCKET中还有没有包的语句。
// return_value=ioctl(sockId,FIONREAD,(ioctlOnPtrTypeCast)bytesAvailable);
int dataLen=0;
int j;
httpCtrlInfo.rcvLen = len;
dataLen=httpParse( );
if(dataLen>0)
{
for(j=0;j<5;j++)
{
len = recv(sock, httpCtrlInfo.rcvBuf+httpCtrlInfo.rcvLen, RCV_BUF_SIZE-httpCtrlInfo.rcvLen, 0);
if (len <= 0)
{
taskDelay(i*10+1);
continue;
}
else
{
httpCtrlInfo.rcvLen += len;
httpParse();
break;
}
}
}
break;
}
}
close(sock);
}
}
void showHttpFile(void)
{
UINT32 i=0;
printf("名称\t\t函数\n");
for(i=0; i<httpFileTable.currentNo; i++)
{
printf("%s\t%d\n", httpFileTable.files[i].fileName,(int) httpFileTable.files[i].createHtmlPage);
}
printf("Current number : %d.\n", httpFileTable.currentNo);
}
void showAction(void)
{
UINT16 i=0;
printf("名称\t\t函数\n");
for(i=0; i<actionTable.currentNo; i++)
{
printf("%s\t%d\n", actionTable.actions[i].actionName, (int)actionTable.actions[i].onPostFunction);
}
printf("Current number : %d.\n", actionTable.currentNo);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?