http_uri处理源码

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kongshuai19900505/article/details/83016962

目录

1 接口总览

 2 构造对象

3 析构对象

4 解析url参数

5 测试


1 接口总览

url处理里面一共3个接口分别是构造对象,url解析以及析构对象

http_uri *http_uri_new(void);   
void http_uri_destroy(http_uri *a_uri);
int http_uri_parse(char *a_uri,http_uri *a_request);

 2 构造对象

http_uri_new构造一个url对象相应结构体在前文已经介绍,这里配置一个默认端口为80

/*
 * 返回值:分配好资源的http_uri内容
 */
http_uri *
http_uri_new(void)
{
    http_uri *l_return = NULL;

    l_return = (http_uri *)malloc(sizeof(http_uri));
    l_return->full = NULL;
    l_return->proto = NULL;
    l_return->host = NULL;
    l_return->port = 80;
    l_return->resource = NULL;
    return l_return;
}

3 析构对象

当分配的资源使用完毕需要释放资源,则使用http_uri_destroy接口

/*
 * 输入参数:http_uri_new分配的http_uri资源
 */
void
http_uri_destroy(http_uri *a_uri)
{
    if (a_uri->full) 
    {
        free(a_uri->full);
        a_uri->full = NULL;
    }

    if (a_uri->proto) 
    {
        free(a_uri->proto);
        a_uri->proto = NULL;
    }

    if (a_uri->host) 
    {
        free(a_uri->host);
        a_uri->host = NULL;
    }

    if (a_uri->resource) 
    {
        free(a_uri->resource);
        a_uri->resource = NULL;
    }
    free(a_uri);
}

4 解析url参数

这里首先用到了一个枚举数据类型:记录解析项

typedef enum uri_parse_state_tag
{
    parse_state_read_host = 0,
    parse_state_read_port,
    parse_state_read_resource
} uri_parse_state;

http_uri_parse源码并不复杂,不过代码中考虑的比较全面,用起来还可以,不过这个解析函数写的并不全面,仅限于“http://ip:pirt/action”这种类型的URL,携带参数的无法解析,并且这个代码解析url的功能,个人感觉写的有些冗余。

/*
 * 输入参数:a_string,url字符串
 * 输出参数:a_uri,http_uri对象资源
 * 返回值: 0-成功 -1-失败
 */
int
http_uri_parse(char *a_string,http_uri *a_uri)
{
    uri_parse_state l_state = parse_state_read_host;
    char *l_start_string = NULL;
    char *l_end_string = NULL;
    char  l_temp_port[6];

    /* init the array */
    memset(l_temp_port, 0, 6);
    if (a_string == NULL)
        goto ec;

    if (a_uri) 
    {
        a_uri->full = strdup(a_string);
    }

    //获取http://1.2.3.4:80/api/login中的第一个":"出现的位置
    l_start_string = strchr(a_string, ':');
    /* 检查确定是否存在":" */
    if (!l_start_string)
        goto ec;
    if (a_uri)//将url中的http字段复制到a_uri->proto里面
    {
        a_uri->proto = (char *)malloc(l_start_string - a_string + 1);
        memcpy(a_uri->proto, a_string, (l_start_string - a_string));
        a_uri->proto[l_start_string - a_string] = '\0';
    }
    /* 检查l_start_string指针的前3个字符是否是"://" */
    if (strncmp(l_start_string, "://", 3) != 0)
        goto ec;
    /* 将l_start_string和l_end_string指针指向url中剩余的部分,也就是ip地址或者域名的首位置,
    这里面l_end_string指针更类似于一个游标,l_start_string为参考起始位置*/
    l_start_string = l_end_string = &l_start_string[3];
    while(*l_end_string)
    {
        if (l_state == parse_state_read_host)
        {
            if (*l_end_string == ':')
            {
                l_state = parse_state_read_port;//状态修改为获取端口
                /*这块代码为什么进行了两次((l_end_string - l_start_string) == 0)检测,不理解*/
                if ((l_end_string - l_start_string) == 0)
                    goto ec;
                /* allocate space */
                if ((l_end_string - l_start_string) == 0)
                    goto ec;
                /* only do this if a uri was passed in */
                if (a_uri)
                {
                    a_uri->host = (char *)malloc(l_end_string - l_start_string + 1);
                    memcpy(a_uri->host, l_start_string, (l_end_string - l_start_string));
                    a_uri->host[l_end_string - l_start_string] = '\0';
                }
                /* reset the counters */
                l_end_string++;//跳过检查的字符":"
                l_start_string = l_end_string;
                continue;
            }
            else if (*l_end_string == '/')
            {
                l_state = parse_state_read_resource;
                if ((l_end_string - l_start_string) == 0)
                    goto ec;
                if (a_uri)
                {
                    a_uri->host = (char *)malloc(l_end_string - l_start_string + 1);
                    memcpy(a_uri->host, l_start_string, (l_end_string - l_start_string));
                    a_uri->host[l_end_string - l_start_string] = '\0';
                }
                l_start_string = l_end_string;
                continue;
            }
        }
        else if (l_state == parse_state_read_port)
        {
            if (*l_end_string == '/')
            {
                l_state = parse_state_read_resource;
                /* l_temp_port空间为6如果大于5说明错误 */
                if (l_end_string - l_start_string > 5)
                    goto ec;
                /* 始末位置相同则数据不存在 */
                if ((l_end_string - l_start_string) == 0)
                    goto ec;
                /* 蒋书记放进缓冲区 */
                memcpy(l_temp_port, l_start_string, l_end_string - l_start_string);
                /* convert it. */
                if (a_uri)
                    a_uri->port = atoi(l_temp_port);
                l_start_string = l_end_string;
                continue;
            }
            else if (isdigit(*l_end_string) == 0)//若参数为阿拉伯数字0~9,则返回非0值,否则返回0
            {
                /* 域名或者IP后面的冒号后面肯定是端口,在没有检索到"/"之前肯定为整数 ,不为整数则说明不是端口号,url出错*/
                goto ec;
            }
        }
        /* next.. */
        l_end_string++;
        continue;
    }

    /*
     1.如果l_state仍然为parse_state_read_host说明url是"http://x.x.x.x",这也是合法的,因为http_uri_new默认端口是80
     1.如果l_state为parse_state_read_port说明url是"http://x.x.x.x:port",这也是合法的,说明访问的resource是根目录
    */
    if (l_state == parse_state_read_host)
    {
        if ((l_end_string - l_start_string) == 0)
            goto ec;
        if (a_uri)
        {
            a_uri->host = (char *)malloc(l_end_string - l_start_string + 1);
            memcpy(a_uri->host, l_start_string, (l_end_string - l_start_string));
            a_uri->host[l_end_string - l_start_string] = '\0';
            a_uri->resource = strdup("/");
        }
    }
    else if (l_state == parse_state_read_port)
    {
        if (strlen(l_start_string) == 0)
            goto ec;
        if (a_uri)
        {
            a_uri->port = atoi(l_start_string);
            a_uri->resource = strdup("/");
        }
    }
    else if (l_state == parse_state_read_resource)
    {
        if (strlen(l_start_string) == 0)
        {
            if (a_uri)
                a_uri->resource = strdup("/");
        }
        else
        {
            if (a_uri)
                a_uri->resource = strdup(l_start_string);
        }
    }
    else
    {
        goto ec;
    }
    return 0;
ec:
    return -1;
}

代码处理流程如下:

5 测试

写了一段测试代码,用起来还不错,代码如下:

void test_url(char *url)
{
    http_uri *uri = http_uri_new();
    http_uri_parse(url,uri);
    if (uri->full) 
        printf("uri->full:\t%s\n",uri->full);

    if (uri->proto) 
        printf("uri->proto:\t%s\n",uri->proto);

    if (uri->host) 
        printf("uri->host:\t%s\n",uri->host);

    if (uri->resource) 
        printf("uri->resource:\t%s\n",uri->resource);
    printf("uri->port:\t%d\n",uri->port);
    http_uri_destroy(uri);
}

int main(int argc, char **argv)
{
    printf("\n#######test:http://1.1.1.1:9999/api/log#######\n");
    test_url("http://1.1.1.1:9999/api/log");
    printf("\n#######test:http://1.1.1.1:9999/##############\n");
    test_url("http://1.1.1.1:9999/");
    printf("\n#######test:http://1.1.1.1:9999###############\n");
    test_url("http://1.1.1.1:9999");
    printf("\n#######test:http://1.1.1.1#####################\n");
    test_url("http://1.1.1.1");
    return 0;
}

代码执行结果如下:

#######test:http://1.1.1.1:9999/api/log#######
uri->full:      http://1.1.1.1:9999/api/log
uri->proto:     http
uri->host:      1.1.1.1
uri->resource:  /api/log
uri->port:      9999

#######test:http://1.1.1.1:9999/##############
uri->full:      http://1.1.1.1:9999/
uri->proto:     http
uri->host:      1.1.1.1
uri->resource:  /
uri->port:      9999

#######test:http://1.1.1.1:9999###############
uri->full:      http://1.1.1.1:9999
uri->proto:     http
uri->host:      1.1.1.1
uri->resource:  /
uri->port:      9999

#######test:http://1.1.1.1#####################
uri->full:      http://1.1.1.1
uri->proto:     http
uri->host:      1.1.1.1
uri->resource:  /
uri->port:      80

猜你喜欢

转载自blog.csdn.net/kongshuai19900505/article/details/83016962