http.c

来自「一个vxworks下http任务socket层的实现代码」· C语言 代码 · 共 850 行 · 第 1/2 页

C
850
字号
#include "vxWorks.h"
#include "stdio.h"
#include "ioLib.h"
#include "inetLib.h"

#include "include/sysdef.h"
#include "maintain/lpt.h"
#include "http.h"

//全局变量
HTTP_FILE_TABLE  httpFileTable;
HTTP_ACTION_TABLE actionTable;


/*****************************************************************************************
 HTTP模块与调用者的接口
 1、addHttpFile   输入页面名称和创建此页面的回调函数
 2、addHttpAction 输入动作名称和解析参数且执行动作的回调函数 
*****************************************************************************************/
STATUS addHttpAction(UINT8 * pActionName, void * pFunction)
{
    UINT16 i;
    
    if(pActionName==NULL || pFunction==NULL)
    {
        lpt(PT_WARN,"param is NULL\n");
        return ERROR;
         
    }

    if(actionTable.currentNo >= MAX_HTTP_ACTION)
    {
        lpt(PT_WARN,"http file table is full!\n");
        return FALSE;
    }
    
    //Check the exist actions.If there already have been a same name action, return
    for(i=0; i<actionTable.currentNo; i++)
    {
        if(strcmp(actionTable.actions[i].actionName, pActionName) == 0)
        {
            lpt1(PT_WARN,"action file %s is already exist\n",pActionName);
            return FALSE;
        }
    }
    
    actionTable.actions[actionTable.currentNo].onPostFunction = (onPostFunctionT)pFunction;
    strcpy(actionTable.actions[actionTable.currentNo].actionName, pActionName);

    actionTable.currentNo++;

    return TRUE;
}

/* 记录安装HTTP文件索引 */
STATUS addHttpFile(UINT8 * pFileName, void * pFunction)
{
    UINT32 i;
    
    if (pFileName == NULL || pFunction == NULL)
    {
        lpt(PT_WARN, "addHttpFile inputerror \n");
        return FALSE;
    }

    if(httpFileTable.currentNo == MAX_HTTP_FILE)
    {
        printf("Http file table is full!\n");
        return FALSE;
    }
    
    //Check the exist files.If there already have been a same name file, return
    for(i=0; i<httpFileTable.currentNo; i++)
    {
        if(strcmp(httpFileTable.files[i].fileName, pFileName) == 0)
        {
            return FALSE;
        }
    }
    
    httpFileTable.files[httpFileTable.currentNo].createHtmlPage = (createHtmlPageT)pFunction;
    strcpy(httpFileTable.files[httpFileTable.currentNo].fileName, pFileName);

    httpFileTable.currentNo++;
    //printf("addHttpFile:%s\n", pFileName);
    return TRUE;
}

/*创建网页出现的状态*/
enum
{
    // 一切正常,对GET和POST请求的应答文档跟在后面。
    HTTP_STATUS_OK = 0,
    // 没有新文档,浏览器应该继续显示原来的文档。
    // 如果用户定期地刷新页面,而Servler可以确定用户文档足够新,这个状态代码是很有用的。 
    HTTP_STATUS_NOCONTENT, // 1
    // 客户请求的文档在其他地方,新的URL在Location头中给出,浏览器应该自动地访问新的URL。
    HTTP_STATUS_MOVEDPERM, // 2
    // 类似于301,但新的URL应该被视为临时性的替代,而不是永久性的。
    HTTP_STATUS_MOVEDTEMP, // 3 
    // 客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。
    // 服务器告诉客户,原来缓冲的文档还可以继续使用。 
    HTTP_STATUS_NOTMODIFIED, // 4
    // 请求出现语法错误。
    HTTP_STATUS_BADREQUEST, // 5
    // 客户试图未经授权访问受密码保护的页面。应答中会包含一个WWW-Authenticate头,
    // 浏览器据此显示用户名字/密码对话框,然后在填写合适的Authorization头后再次发出请求。 
    HTTP_STATUS_UNAUTHORIZED, // 6
    // 资源不可用。服务器理解客户的请求,但拒绝处理它。通常由于服务器上文件或目录的权限设置导致。
    HTTP_STATUS_FORBIDDEN, // 7
    // 无法找到指定位置的资源。这也是一个常用的应答。
    HTTP_STATUS_NOTFOUND, // 8
    // 服务器遇到了意料不到的情况,不能完成客户的请求。
    HTTP_STATUS_SERVERERROR, // 9
    // 服务器不支持实现请求所需要的功能。例如,客户发出了一个服务器不支持的PUT请求。 
    HTTP_STATUS_NOTIMPLEMENTED, // 10
    HTTP_STATUS_END,
};

// HTTP状态描述,必须与E_HTTP_STATE对应。
static char httpStateDes[HTTP_STATUS_END][50] = 
{
    {"HTTP/1.1 200 OK\r\n"},
    {"HTTP/1.1 204 No Content\r\n"},
    {"HTTP/1.1 301 Moved Permanently\r\n"},
    {"HTTP/1.1 302 Moved Temporarily\r\n"},
    {"HTTP/1.1 304 Not Modified\r\n"},
    {"HTTP/1.1 400 Bad Request\r\n"},
    {"HTTP/1.1 401 Unauthorized\r\n"},
    {"HTTP/1.1 403 Forbidden\r\n",},
    {"HTTP/1.1 404 Not Found\r\n"},
    {"HTTP/1.1 500 Internal Server Error\r\n"},
    {"HTTP/1.1 501 Not Implemented\r\n"},
};

HTTP_CTRL_INFO httpCtrlInfo;

// HTTP回送应答状态
void httpSndState(int state)
{
    if (state >= HTTP_STATUS_END)
    {
        lpt1(PT_WARN, "http state %d error \n", state);
        return;
    }

    send(httpCtrlInfo.connectSock, httpStateDes[state], strlen(httpStateDes[state]), 0);
}

//采用标准的头格式,从而支持不同版本的IE和多种文件,如voip.sys,voip.log可以直接下载
void httpSndFileHead(char * fileName)
{
    char stringBuf[200];
    char fileType[30];
    memset(fileType,0,sizeof(fileType));
    if(fileName==NULL)
    {
    	strcpy(fileType,"text/html");//默认的方式
    }
    /*******************XML和其样式表**********************/
    else if((strstr(fileName, ".xml") !=0) || (strstr(fileName,".xsl" ) != 0))
    {
    	strcpy(fileType,"text/xml");
    }
    /*******************html和其样式表**********************/
    else if((strstr(fileName, ".html") !=0) ||(strstr(fileName, ".htm") !=0))
    {
    	strcpy(fileType,"text/html");
    }
    else if(strstr(fileName, ".css") !=0)
    {
    	strcpy(fileType,"text/css");
    }
    /*******************javascript**********************/
    else if(strstr(fileName, ".js") !=0)
    {
    	strcpy(fileType,"application/x-javascript");
    }
    /*******************常见的图象格式**********************/
    else if(strstr(fileName, ".ico") !=0)
    {
    	strcpy(fileType,"image/x-icon");
    }
    else if((strstr(fileName, ".jpg") !=0) || (strstr(fileName,".jpeg" ) != 0) || (strstr(fileName,".jpe" ) != 0))
    {
    	strcpy(fileType,"image/jpeg");
    }
    else if(strstr(fileName, ".bmp") !=0)
    {
    	strcpy(fileType,"image/bmp");
    }
    else if(strstr(fileName, ".gif") !=0)
    {
       strcpy(fileType,"image/gif");
    }
    else
    {
        strcpy(fileType,"application/x-msdownload");
    }
    
    memset(stringBuf, 0, sizeof(stringBuf));

    strcpy(stringBuf, "Server: KEDACOM VoIP 4.0\r\n");
    strcat(stringBuf,"Content-Type: ");
    strcat(stringBuf, fileType);
    strcat(stringBuf, "\r\n\r\n");

    send(httpCtrlInfo.connectSock, stringBuf, strlen(stringBuf), 0);
}

//目前在发送大量数据的时候会出现发不成功的问题
void httpSndContent(char * buf, int len)
{
    int i;
    int sendSuccessBytes, sendOnceBytes, rv;

    if (buf == NULL || len < 0)
    {
        lpt(PT_WARN, "httpSndContent input error \n");
        return;
    }

    sendSuccessBytes = 0;
    while (sendSuccessBytes < len)
    {
        sendOnceBytes = len - sendSuccessBytes;

        if (sendOnceBytes > 1024)
        {
            // 一次不能发的太多
            sendOnceBytes = 1024; 
        }
        //rv可能发送失败,连续5次发包
        for(i=0;i<5;i++)
        {
        	rv = send(httpCtrlInfo.connectSock,buf+sendSuccessBytes,sendOnceBytes,0);
        	if(rv>0)
        	{
                break;
        	}
        	else
        	{
                taskDelay(i*5+10);
        	}
        }
        if(i==5)
        {
        	 lpt(PT_WARN ,"send error \n");
        	 return;
        }

        sendSuccessBytes+=rv;

        if (rv < sendOnceBytes)
        {
            // 实际发送成功的字节数小于准备发送的字节数,说明网络太忙,需延迟一下。
            taskDelay(6);
        }
    }
}

//发送异常情况的页面------通常用到的几种
void httpSndNotFindFile(void)
{
    UINT8 content[120];
    memset(content,0,sizeof(content));
    strcpy(content,"<html><head>");
    strcat(content,"<title>Object Not Found</title></head>");
    strcat(content,"<body><h1>HTTP/1.1 404 Object Not Found</h1></body>");
    strcat(content,"</html>");
    httpSndState(HTTP_STATUS_NOTFOUND);
    httpSndFileHead("httperr404.html");
    httpSndContent(content,strlen(content));
}

void httpSndNotAuthorization(void)
{
    UINT8 stringBuf[200];

    memset(stringBuf,0,sizeof(stringBuf));
    strcpy(stringBuf, "Server: KEDACOM VoIP 4.0\r\n");
    //strcat(stringBuf,"WWW-Authenticate: Negotiate\r\n");//对于NT的域认证,我们正常用不到
    //strcat(stringBuf,"WWW-Authenticate: NTLM\r\n");
    strcat(stringBuf,"WWW-Authenticate: Basic realm=苏  州  科  达  科  技\r\n");
    strcat(stringBuf,"Cache-control: no-cache\r\n");
    httpSndState(HTTP_STATUS_UNAUTHORIZED);
    httpSndContent(stringBuf,strlen(stringBuf));
}

void httpSndForbiddenAccess(void)
{
    UINT8 content[120];

    memset(content,0,sizeof(content));
    strcpy(content,"<html><head>");
    strcat(content,"<title>Directory Listing Denied</title></head>");
    strcat(content,"<body><h1>Directory Listing Denied</h1>This Virtual Directory does not allow contents to be listed.</body>");
    strcat(content,"</html>");
    httpSndState(HTTP_STATUS_FORBIDDEN);
    httpSndFileHead("httperr403.html");
    httpSndContent(content,strlen(content));
}


//action table fuction
void initActionTable(void)
{
    UINT32 i;
    memset(&actionTable, 0, sizeof(actionTable));

    for(i=0; i<MAX_HTTP_ACTION; i++)
    {
        actionTable.actions[i].onPostFunction = NULL;
    }
}


/* 初始化WEB服务要用到的文件索引 */
void initHttpFileTable(void)
{
    UINT32 i;
    memset(&httpFileTable, 0, sizeof(httpFileTable));

    for(i=0; i<MAX_HTTP_FILE; i++)
    {
        httpFileTable.files[i].createHtmlPage = NULL;
    }
}

//启动HTTP服务,创建SOCKET
int httpServListen(void )
{
    struct sockaddr_in local;
    int s;
    const int on = 1;
    
    local.sin_port = 80;
    local.sin_addr.s_addr = htonl (INADDR_ANY);
    if((s = socket(AF_INET, SOCK_STREAM, 0)) == ERROR)
    {
        printf("startHTTP socket:");
        printErrno(errno);
        return ERROR;
    }
    
    if(s<=0)
    { 
        printf("socket call failed\n");
        return ERROR;
    }

    if(bind(s, (struct sockaddr *) &local, sizeof(local)) == ERROR)
    {
        printf("startHTTP bind:");
        printErrno(errno);
        if(close(s) == ERROR)
        {
            printf("startHTTP close:");
            printErrno(errno);
            return ERROR;
        }
        return ERROR;
    }

    if(listen(s, 5) == ERROR )
    {
       printf("startHTTP listen:");printErrno(errno);
	if(close(s) == ERROR)
	{
	    printf("startHTTP listen close:");printErrno(errno);
	    return ERROR;
	}
       return ERROR;
    }

    return s;
}

int getHttpAction(UINT8 * pActionName)
{
    UINT16 i;
    
    if(pActionName==NULL)
    {
        lpt(PT_WARN,"param is NULL\n");
        return -1;
         
    }
    
    if(pActionName == NULL)
    {
        lpt(PT_WARN,"param is NULL\n");
        return -1;
    }

    for(i=0; i<actionTable.currentNo; i++)
    {
        if(strcmp(actionTable.actions[i].actionName, pActionName) == 0)
        {
            return i;
        }
    }

    lpt1(PT_WARN,"can not find action %s\n",pActionName);
    return -1;
}

int getHttpFile(UINT8 * pFileName)
{
    UINT32 i;
    
    if (pFileName == NULL)
    {
        lpt(PT_WARN, "getHttpFile input is null \n");
        return ERROR;
    }
        
    for(i=0; i<httpFileTable.currentNo; i++)
    {
        if(strcmp(httpFileTable.files[i].fileName, pFileName) == 0)
        {
            return i;
        }
    }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?