summaryrefslogtreecommitdiffabout
path: root/src/util.cc
blob: 76e684f4b62eea6d952da040e3e88ae194a1fc7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <cstring>
#include "kingate/util.h"
#include "kingate/exception.h"

namespace kingate {

    static const char *safeChars = 
	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	"abcdefghijklmnopqrstuvwxyz"
	"0123456789"
	"_-" ;

    string url_encode(const string& str) {
	string rv = str;
	string::size_type screwed = 0;
	for(;;) {
	    screwed = rv.find_first_not_of(safeChars,screwed);
	    if(screwed == string::npos)
		break;
	    while(screwed<rv.length() && !strchr(safeChars,rv.at(screwed))) {
		char danger = rv.at(screwed);
		if(danger==' ') {
		    rv.replace(screwed++,1,1,'+');
		}else{
		    static char tmp[4] = {'%',0,0,0};
		    snprintf(&tmp[1],3,"%02X",0xFF&(int)danger);
		    rv.replace(screwed,1,tmp,3);
		    screwed+=3;
		}
	    }
	}
	return rv;
    }
    string url_decode(const string& str) {
	string rv = str;
	string::size_type unscrewed = 0;
	for(;;) {
	    unscrewed = rv.find_first_of("%+",unscrewed);
	    if(unscrewed == string::npos)
		break;
	    if(rv.at(unscrewed)=='+') {
		rv.replace(unscrewed++,1,1,' ');
	    }else{
		if((rv.length()-unscrewed)<3)
		    throw exception(CODEPOINT,"incorrectly escaped string");
		// XXX: ensure it's hex?
		int danger = strtol(rv.substr(unscrewed+1,2).c_str(),NULL,16);
		rv.replace(unscrewed,3,1,danger);
		unscrewed++;
	    }
	}
	return rv;
    }

    /*
     * RFC 2616:
     *
     *        separators     = "(" | ")" | "<" | ">" | "@"
     *                       | "," | ";" | ":" | "\" | <">
     *                       | "/" | "[" | "]" | "?" | "="
     *                       | "{" | "}" | SP | HT
     */
    
    /*
     * RFC 2616:
     *
     *        token          = 1*<any CHAR except CTLs or separators>
     */

    static const char *quotible_chars =
	"\001\002\003\004\005\006\007\010"
	"\011\012\013\014\015\016\017\020"
	"\021\022\023\024\025\026\027\030"
	"\031\032\033\034\035\036\037\040"
	"()<>@,;:\\\"/[]?={}" /* separator chars (except for SP and HT mentioned elsewhere */
	"\177"
	;

    /*
     * RFC 2616:
     *
     *        quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> )
     *        qdtext         = <any TEXT except <">>
     *
     *    The backslash character ("\") MAY be used as a single-character
     *    quoting mechanism only within quoted-string and comment constructs.
     *
     *        quoted-pair    = "\" CHAR
     */

    string http_quoted_string(const string& str) {
	string rv = str;
	string::size_type sp=0;
	for(string::size_type q=rv.find('"');(q=rv.find('"',q))!=string::npos;q+=2)
	    rv.insert(q,1,'\\');
	rv.insert(0,1,'"');
	rv += '"';
	return rv;
    }

    string http_quote(const string& str) {
	if(str.find_first_of(quotible_chars)==string::npos)
	    return str;
	return http_quoted_string(str);
    }

}