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 + -
显示快捷键?