http_uri处理源码

目录

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

 

以下是将 Ruby 代码转换为 ASP.NET 源码的示例: ```csharp using System.Collections.Generic; using System.Net; using System.Text; var urls = new List<string> { "http://www.example.com/1.html", "http://www.example.com/2.html" }; var url = "http://data.zz.baidu.com/urls?site=https://3gqq.cn&token=LA8UpYR7d3zCQ2RL"; var request = WebRequest.Create(url) as HttpWebRequest; request.Method = "POST"; request.ContentType = "text/plain"; var postData = string.Join("\n", urls); var encoding = new UTF8Encoding(); var bytes = encoding.GetBytes(postData); request.ContentLength = bytes.Length; using (var requestStream = request.GetRequestStream()) { requestStream.Write(bytes, 0, bytes.Length); } using (var response = request.GetResponse() as HttpWebResponse) { var responseStream = response.GetResponseStream(); var reader = new StreamReader(responseStream, Encoding.UTF8); var responseString = reader.ReadToEnd(); // 处理响应内容 } ``` 这段代码使用了 .NET Framework 内置的 `HttpWebRequest` 类来向百度搜索引擎发送推送请求。其中,`urls` 和 `url` 分别表示待推送链接列表和推送请求的 URL。通过 `request.Method` 设置请求方法为 POST,`request.ContentType` 设置请求头中的 Content-Type 参数,`request.ContentLength` 设置请求体的长度,模拟了 Ruby 代码中的请求设置。最后,通过 `request.GetRequestStream` 方法获取请求流,将待推送链接列表写入请求流中,并通过 `request.GetResponse` 方法获取响应对象,从响应流中读取响应内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值