在web服务器中,通常要设计很多字符串的处理。比如客户端请求的 URI地址、发送的 query参数、post 提交的数据等等都是一串字符。因此,提供对字符串的灵活高效的处理,对lighttpd的效率至关重要。
在lighttpd中,buffer提供了对字符串的处理。在buffer.h中,有如下的数据结构定义:
//定义buffer
1 typedef struct 
2 {
3     char *ptr;     //指向存储空间,一个字符串组
4     size_t used;     //buffer中数据的长度
5     size_t size;     //buffer的长度
6 } buffer;
上面的结构体定义了lighttpd中,对字符串处理的基本结构。其具体含义如上。
17 }read_buffer
这个结构体比较有意思,具体干什么的我还没有发现。。。不过从其定义中猜测,应该和输入输出缓冲有关。

围绕buffer结构体和buffer_array结构体,在buffer.h中定义了很多操作函数,其具体的作用将在下文中一一说明。其中比较有意思有技巧的函数还将就其实现代码进行分析。大部分的函数都很简单,读者可以自行阅读。
首先是buffer_array的操作函数:
1、buffer_array *buffer_array_init(void);
初始化一个buffer_array,返回其指针并分配空间。
2、void buffer_array_free(buffer_array * b);
释放b指向的buffer_array的空间。
3、void buffer_array_reset(buffer_array * b);
重置buffer_array。并递归重置数组中的数据。
4、buffer *buffer_array_append_get_buffer(buffer_array * b);
返回数组中第一个未使用的buffer结构体的指针。如果数组已满,则对数组进行扩容,并初始化第一个为使用的buffer的指针。

下面是buffer的操作函数:
1、buffer *buffer_init(void);
初始化一个buffer。
2、buffer *buffer_init_buffer(buffer * b);
用b初始化一个buffer。相当于复制b。
3、buffer *buffer_init_string(const char *str);
用str初始化一个buffer。把str指向的字符串复制到buffer中。
4、void buffer_free(buffer * b);
释放buffer的空间。
5、void buffer_reset(buffer * b);
这个比较有意思。重置b所指向的buffer结构。一般情况下,都是把buffer数据区中ptr指向的字符数组的第一个元素ptr[0]设置为’\0’,然后把buffer的size设置为0。但当buffer的大小超过BUFFER_MAX_REUSE_SIZE时,则直接释放buffer的ptr指向的空间并把size设置为0。
6、int buffer_prepare_copy(buffer * b, size_t size);
为复制准备size大小的空间。如果b的空间大于size则仅仅将b的使用空间used设置为0.如果b的空间小于size,则重新分配size大小的空间。另外,为了防止内存碎片,在每次重新分配空间时,都将所分配的空间凑成BUFFER_PIECE_SIZE的整数倍:
1 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
7、int buffer_prepare_append(buffer * b, size_t size);
为追加size大小的数据准备空间。操作和上一个函数查不多。
8、int buffer_copy_string(buffer * b, const char *s);
将字符串s复制到b中。
9、int buffer_copy_string_len(buffer * b, const char *s, size_t s_len);
将字符串s复制到b中。s_len是s的长度。s被看作是一个不以'\0'结尾的字符串,s_len是s的长度。最终b中的数据以'\0'结尾。也就是说,如果s的结尾是'\0',那么,最终,b中的数据末尾有两个'\0',而且b中used表示的数据长度,包括其中一个'\0'!
10、int buffer_copy_string_buffer(buffer * b, const buffer * src);
将src中的数据复制到b中。
11、int buffer_copy_string_hex(buffer * b, const char *in ,size_t in_len);
将字符串In转化成十六进制形式,复制到b中。
12、int buffer_copy_long(buffer * b, long val);
将val以字符串的形式复制到b中。
13、int buffer_copy_memory(buffer * b, const char *s, size_t s_len);
复制s指向的内存区域中的数据到b中。
14、int buffer_append_string(buffer * b, const char *s);
将字符串s追加大b中。
15、int buffer_append_string_len(buffer * b, const char *s, size_t s_len);
将字符串s追加到b中。s_len为s的长度。
具体的处理与上面的复制函数差不多。
16、int buffer_append_string_buffer(buffer * b, const buffer * src);
将src的数据追加到b中。
17、int buffer_append_string_lfill(buffer * b, const char *s, size_t maxlen);
这个函数在buffer.c中没有实现。
18、int buffer_append_string_rfill(buffer * b, const char *s, size_t maxlen);
将字符串s追加到b中。其中maxlen为字符串s的最大长度。如果
字符串s的长度小于maxlen,那么追加空格,使其长度达到maxlen。在 函数实现中。如果s的长度大于maxlen,则可能溢出。。。
19、int buffer_append_long_hex(buffer * b, unsigned long len);
将无符号长整型value转化成对应的十六进制的字符串形式。并将字符串复制到b中。其中涉及到数值转16进制的问题。代码如下:
39 
20、int buffer_append_long(buffer * b, long val);
将val以字符串的形式追加大b中。
 
下面的宏定义使用来处理off_t和long类型。
如果long和off_t相同,则用处理long的函数来处理off_t。如果不相同,则另行定义off_t的处理函数。

22、int buffer_append_memory(buffer * b, const char *s, size_t s_len);
将s指向的内存区的数据复制到b中,s_len是s的长度。
23、char *buffer_search_string_len(buffer * b, const char *needle, size_t len);
判断b中是否含有字符串needle,needle的长度为len。如果存在,则返回needle在b中的指针位置,否则返回NULL
24、int buffer_is_empty(buffer * b);
判断b是否为空。
25、int buffer_is_equal(buffer * a, buffer * b);
判断a和b中的数据是相同。
26、int buffer_is_equal_right_len(buffer * a, buffer * b, size_t len);
判断b1和b2中,最右边的len个字符是否相同。
27、int buffer_is_equal_string(buffer * a, const char *s, size_t b_len);
b中的数据是否等于s,b_len为s的长度。
28、int buffer_caseless_compare(const char *a, size_t a_len,const char *b, size_t b_len);
比较字符串a和b,忽略大小写。

buffer_caseless_compare /** deprecated */

一些工具性的函数:
1、int LI_ltostr(char *buf, long val);
将长整型val转化成字符串,并存入buf中。
2、char hex2int(unsigned char c);
converts hex char (0-9, A-Z, a-z) to decimal.returns 0xFF on 
invalid input. 将16进制的字符转化成对应的数字,非法输入返回0xFF。忽略c的大小写。
3、char int2hex(char i);
将i转化成对应的16进制形式
4、int light_isdigit(int c);
c是否是数字。0-9
5、int light_isxdigit(int c);
c是否是十六进制的数字0-9 a-f
6、int light_isalpha(int c);
c是否是字母。
7、int light_isalnum(int c);
c是否是字母或数字。
以上几个函数在处理大小写的时候,都使用了c |= 32;将c转换成小写的形式,无论c原来是大写还是小写。原理在函数buffer_caseless_compare中讲解过。
8、int buffer_to_lower(buffer * b);
将b中的数据转换成小写。
9、int buffer_to_upper(buffer * b);
将b中的数据转换成大写。
以上两个函数没有在buffer.c中定义。

下面的几个宏定义一些方便的操作。
以下的函数操作涉及到编码问题。在lighttpd中,使用到的编码有六种。具体的类型定义在下面的结构体中。
于此对应的 buffer.c 源文件中给出了 
const char encoded_chars_rel_uri_part[]
const char encoded_chars_rel_uri[]
const char encoded_chars_html[]
const char encoded_chars_minimal_xml[]
const char encoded_chars_hex[]
const char encoded_chars_http_header[] 
六个标志数组,数组中值为 1 的元素表示对应下标值大小的字符需要被编码转换,否则不需要转换可以直接使用(即编码前和编码后是同一个值)。例如对于 encoded_chars_rel_uri数组,encoded_chars_rel_uri[32]值为1表示该对应的字符(32对应的是空格,因为空格的十进制值为 32)需要被 uri 编码(被编码为“%20”),而对于值为 0的 encoded_chars_rel_uri[48],其对应的字符就不需要编码(48 对应的是字符‘0’,而字符‘0’并不是特殊字符,因此不用编码。)。对于具体的编码方式,请查阅相关资料。
1、int buffer_append_string_encoded(buffer * b, const char *s,size_t s_len, buffer_encoding_t encoding);
    将字符串s以指定的编码方式存入b中。encoding指定编码的方式。
2、static int buffer_urldecode_internal(buffer *url, int is_query)
    将rul中存放的特殊编码的字符转换成正常的字符。这里的编码是指上面六种编码中的ENCODING_REL_RUL_PART.

3、int buffer_path_simplify(buffer * dest, buffer * src);
    删除路径字符串中的"/../","//"和"/./",简化路径,并不是简单的删除。

总得来说,buffer的内容比较简单,其他的函数读者可以自行查看。

相关文章:

  • 2021-11-12
  • 2021-07-27
  • 2021-12-20
  • 2022-01-19
  • 2021-06-04
  • 2022-02-26
  • 2021-07-07
  • 2021-06-11
猜你喜欢
  • 2022-02-27
  • 2021-11-15
  • 2022-01-15
  • 2021-08-23
  • 2021-11-28
相关资源
相似解决方案