目录
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