字符集合
依據
RFC3986 2規范,HTTP URI中允許出現的US-ASCII字符的子集,可以分成
保留、
未保留及
轉義這幾類,每類的全部字符列表如下
● 保留:
: / ? # [ ] @ ! $ & '( ) * + ,; =共18個,一般用于URI部件分隔符。
● 未保留:
a-z A-Z 0-9 - . _ ~共66個,一般用于部件內數據。
● 轉義:
%HEXHEX,HEX表示一個十六進制數字[0-9A-F]或[0-9a-f],通常采用大寫,這兩個HEX就表示一個US-ASCII字符代碼,轉義用于在URI內部插入保留字符及原本不支持的字符。
編碼原理
當構建URI的部件時,其中的一個八位字節碼相應的字符超出了允許的集合或被用作分隔符,就需要編碼,正是在這個時候,由實現決定保留字符的哪些被用于子部件分隔符,哪個被安全地用于數據。一個百分號編碼的八位字節碼被編碼成一個三重字符, 包括百分號字符"%"和隨后的兩個十六進制數字展示那個八位字節的數值。
字符映射表
用于快速判斷一個字符是否為未保留字符,定義如下
1
const char http_uri_table[256] =
2

{
3
/**//* 0 */
4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
7
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
8
/**//* 64 */
9
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
10
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
11
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
12
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
13
/**//* 128 */
14
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
15
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
18
/**//* 192 */
19
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
20
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
21
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
22
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
23
};
24
#define HTTP_CHAR_IS_UNRESERVED(c) (http_uri_table[(unsigned char)(c)])
接口實現
http_uri_encode有2個版本:一個帶uri長度參數len,另一個則不帶。
1
void http_uri_encode(const char *uri, size_t len, std::string &str,bool space_as_plus/**//*=false*/)
2

{
3
char c,buf[4];
4
5
for (size_t i = 0; i < len; i++)
{
6
c = uri[i];
7
if (HTTP_CHAR_IS_UNRESERVED(c))
{
8
str.push_back(c);
9
}else if(c == ' ' && space_as_plus)
{
10
str.push_back('+');
11
}else
{
12
sprintf(buf,"%%%02X",(unsigned char)c);
13
str.append(buf);
14
}
15
}
16
}
17
18
void http_uri_encode(const char *uri, std::string &str,bool space_as_plus/**//*=false*/)
19

{
20
char c,buf[4];
21
22
for (; c=*uri; ++uri)
{
23
if (HTTP_CHAR_IS_UNRESERVED(c))
{
24
str.push_back(c);
25
}else if(c == ' ' && space_as_plus)
{
26
str.push_back('+');
27
}else
{
28
sprintf(buf,"%%%02X",(unsigned char)c);
29
str.append(buf);
30
}
31
}
32
}
解碼原理
當解析URI的時候,首先要根據HTTP協議分離各個部件,再將各部件內可能的轉義數據進行反轉義以還原。
接口實現
http_uri_decode有2種版本,一種提供存儲解碼后的uri參數str;另一種則不提供即在原uri上解碼,返回實際解碼后的字節數。每種版本又有2個版本,一個帶uri長度參數len,另一個則不帶。
1
void http_uri_decode(const char *uri, size_t len, std::string &str, int decode_plus /**//*= 0*/)
2

{
3
char c,t[3]=
{'\0'};
4
5
for (size_t i = 0; i < len; i++)
{
6
c = uri[i];
7
if (c == '?')
{
8
if(decode_plus < 0)
9
decode_plus = 1;
10
} else if (c == '+' && decode_plus)
{
11
c = ' ';
12
} else if (c == '%' && isxdigit(uri[i+1]) && isxdigit(uri[i+2]))
{
13
t[0] = uri[++i],t[1] = uri[++i];
14
c = (char)strtol(t, NULL, 16);
15
}
16
str.push_back(c);
17
}
18
}
19
20
void http_uri_decode(const char *uri, std::string &str, int decode_plus/**//*=0*/)
21

{
22
char c,t[3]=
{'\0'};
23
24
for (; c=*uri; ++uri)
{
25
if (c == '?')
{
26
if(decode_plus < 0)
27
decode_plus = 1;
28
} else if (c == '+' && decode_plus)
{
29
c = ' ';
30
} else if (c == '%' && isxdigit(*(uri+1)) && isxdigit(*(uri+2)))
{
31
t[0] = *++uri,t[1] = *++uri;
32
c = (char)strtol(t, NULL, 16);
33
}
34
str.push_back(c);
35
}
36
}
37
38
//in place decode function
39
size_t http_uri_decode(char *uri, size_t len, int decode_plus/**//*=0*/)
40

{
41
char c,t[3]=
{'\0'};
42
size_t i,j;
43
44
for (i=j=0; i < len; ++i,++j)
{
45
c = uri[i];
46
if (c == '?')
{
47
if(decode_plus < 0)
48
decode_plus = 1;
49
} else if (c == '+' && decode_plus)
{
50
c = ' ';
51
} else if (c == '%' && isxdigit(uri[i+1]) && isxdigit(uri[i+2]))
{
52
t[0] = uri[++i],t[1] = uri[++i];
53
c = (char)strtol(t, NULL, 16);
54
}
55
uri[j] = c;
56
}
57
58
uri[j] = '\0';
59
return j;
60
}
61
62
size_t http_uri_decode(char *uri,int decode_plus/**//*=0*/)
63

{
64
char c,*s=uri,*d=uri,t[3]=
{'\0'};
65
66
for (; c=*s; ++s,++d)
{
67
if (c == '?')
{
68
if(decode_plus < 0)
69
decode_plus = 1;
70
} else if (c == '+' && decode_plus)
{
71
c = ' ';
72
} else if (c == '%' && isxdigit(*(s+1)) && isxdigit(*(s+2)))
{
73
t[0] = *++s,t[1] = *++s;
74
c = (char)strtol(t, NULL, 16);
75
}
76
*d = c;
77
}
78
79
*d= '\0';
80
return d-uri;
81
}
posted on 2015-02-10 18:40
春秋十二月 閱讀(4737)
評論(1) 編輯 收藏 引用 所屬分類:
Network