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

 

<think>好的,用户现在想了解如何在Yocto项目的配方文件中编写SRC_URI来从某个网站获取引导资源。首先,我需要确认用户对Yocto的基础知识是否了解。不过用户已经提到了SRC_URI,所以可能有一定的经验,但可能需要具体示例。 用户之前的问题是关于uboot的Licenses/README文件的位置,现在转向了Yocto的资源获取,这可能意味着他们在进行嵌入式系统的构建,需要配置不同的引导程序,比如U-Boot。因此,他们可能需要知道如何正确指定源码的下载路径。 首先,我应该回忆Yocto中的SRC_URI的常见写法。SRC_URI用于指定源代码的位置,可以是远程URL、本地文件或版本控制系统。用户提到从某个网站获取,所以重点放在HTTP/FTP的URL格式。 需要说明基本语法,比如使用http://或https://,以及如何处理不同的压缩格式,比如.gz或.zip。同时,可能需要提到如何添加校验和(如SHA256),因为Yocto在获取资源时会检查校验和,如果缺失会导致错误。 另外,用户可能需要知道如何指定下载后的文件名,特别是当URL中的文件名与预期的不同时,可以使用“downloadfilename”参数。此外,如果资源需要认证,可能需要添加认证信息,但要注意安全风险。 还要考虑特殊情况,比如从Git仓库获取代码,这时候需要使用git协议,并指定分支和标签。不过用户明确提到从网站获取,所以可能主要是静态文件的下载,比如预编译的二进制文件或源码包。 还需要提醒用户注意网络访问权限,确保构建时能够访问指定的URL,以及如何处理可能的代理设置。另外,如果资源较大,可能需要考虑使用共享下载目录(DL_DIR)来缓存文件,加快后续构建速度。 最后,应该给出一个或多个具体的例子,比如下载一个压缩包,或者从GitHub Releases获取文件。同时,强调校验和的重要性,并提供如何生成校验和的方法,比如使用sha256sum命令。 可能还需要提醒用户,如果自定义的boot资源需要打补丁或进行其他处理,可以在SRC_URI中添加补丁文件,并在配方中指定相应的任务。不过用户当前的问题可能主要集中在获取资源这一步,所以保持回答集中在SRC_URI的写法上。 总结,回答的结构应该包括基本语法、参数说明、示例以及注意事项,确保用户能够根据具体需求调整URL和相关参数,并正确处理校验和和文件名的问题。</think>在 Yocto 项目中,若要从远程网站获取 boot 资源(如 U-Boot、内核等),需要在配方文件(`.bb` 或 `.bbappend`)中通过 `SRC_URI` 字段指定资源地址。以下是常见场景的写法示例: --- ### **1. 基础语法** ```bitbake SRC_URI = "http://example.com/path/to/boot-resource.tar.gz" ``` - 支持协议:`http`、`https`、`ftp`、`git`、`file`(本地文件)等 - 自动解压:若文件是 `.tar.gz`、`.zip` 等压缩格式,Yocto 会自动解压 --- ### **2. 常用参数扩展** #### **(1) 指定文件名** 若 URL 中的文件名与预期不符,可重命名: ```bitbake SRC_URI = "http://example.com/path/to/resource?v=1.0;downloadfilename=custom-name.tar.gz" ``` #### **(2) 校验和(必需)** Yocto 要求提供校验和(否则会报错): ```bitbake SRC_URI[sha256sum] = "a1b2c3d4e5f6..." ``` 生成校验和命令: ```bash sha256sum your-file.tar.gz ``` #### **(3) 认证信息(需谨慎)** 若需用户名/密码: ```bitbake SRC_URI = "http://user:password@example.com/path/to/resource" ``` > **警告**:明文存储密码不安全,建议通过 `BB_NO_NETWORK` 或私有网络规避。 --- ### **3. 典型场景示例** #### **(1) 下载压缩包** ```bitbake SRC_URI = "https://github.com/u-boot/u-boot/archive/refs/tags/v2023.10.tar.gz" SRC_URI[sha256sum] = "d2e7fb73d9d2a8e2dde950c1d3f65c8e9d8c8b1d6a8f8e9c6a5b4c3d2a1b0" ``` #### **(2) 从 Git 仓库获取** ```bitbake SRC_URI = "git://git.example.com/bootloader.git;protocol=https;branch=main" SRCREV = "a1b2c3d4e5f6..." # 指定提交哈希或标签 ``` #### **(3) 多资源混合使用** ```bitbake SRC_URI = " \ http://example.com/u-boot.bin \ git://git.example.com/kernel.git;protocol=ssh;name=kernel \ file://local-patch.patch \ " ``` --- ### **4. 注意事项** 1. **网络访问权限**:确保构建主机能访问目标 URL(检查防火墙/代理) 2. **依赖项**:若资源需 `wget` 或 `git`,需在配方中添加: ```bitbake DEPENDS += "wget-native git-native" ``` 3. **调试**:若下载失败,检查 `build/tmp/work/` 下的日志文件。 --- 如果需要具体到某个资源(如特定 U-Boot 版本),可提供更多细节,我会给出针对性示例!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值