summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--src/cgi_gateway.cc1
-rw-r--r--src/fastcgi.cc1
-rw-r--r--src/plaincgi.cc1
-rw-r--r--src/util.cc1
4 files changed, 4 insertions, 0 deletions
diff --git a/src/cgi_gateway.cc b/src/cgi_gateway.cc
index a2681aa..3763654 100644
--- a/src/cgi_gateway.cc
+++ b/src/cgi_gateway.cc
@@ -1,195 +1,196 @@
1#include <errno.h> 1#include <errno.h>
2#include <ctype.h> 2#include <ctype.h>
3#include <sstream> 3#include <sstream>
4#include <cstring>
4#include "kingate/cgi_gateway.h" 5#include "kingate/cgi_gateway.h"
5#include "kingate/util.h" 6#include "kingate/util.h"
6#include "kingate/exception.h" 7#include "kingate/exception.h"
7#include "config.h" 8#include "config.h"
8#ifdef HAVE_MIMETIC 9#ifdef HAVE_MIMETIC
9# include <mimetic/mimeentity.h> 10# include <mimetic/mimeentity.h>
10# include <mimetic/parser/itparser.h> 11# include <mimetic/parser/itparser.h>
11#endif /* HAVE_MIMETIC */ 12#endif /* HAVE_MIMETIC */
12 13
13namespace kingate { 14namespace kingate {
14 15
15#ifdef HAVE_MIMETIC 16#ifdef HAVE_MIMETIC
16 using mimetic::MimeEntity; 17 using mimetic::MimeEntity;
17 18
18 struct TornMimeEntity : public MimeEntity { 19 struct TornMimeEntity : public MimeEntity {
19 typedef istreambuf_iterator<char> it_type; 20 typedef istreambuf_iterator<char> it_type;
20 typedef it_type::iterator_category it_cat; 21 typedef it_type::iterator_category it_cat;
21 struct IParser : public mimetic::IteratorParser<it_type,it_cat> { 22 struct IParser : public mimetic::IteratorParser<it_type,it_cat> {
22 typedef mimetic::IteratorParser<it_type,it_cat> BT; 23 typedef mimetic::IteratorParser<it_type,it_cat> BT;
23 IParser(MimeEntity& me) 24 IParser(MimeEntity& me)
24 : BT::IteratorParser<it_type,it_cat>(me) { } 25 : BT::IteratorParser<it_type,it_cat>(me) { }
25 void loadHeader(it_type bit,it_type eit) { 26 void loadHeader(it_type bit,it_type eit) {
26 m_bit = bit; m_eit = eit; 27 m_bit = bit; m_eit = eit;
27 BT::loadHeader(); 28 BT::loadHeader();
28 } 29 }
29 void loadBody(it_type bit,it_type eit) { 30 void loadBody(it_type bit,it_type eit) {
30 m_bit = bit; m_eit = eit; 31 m_bit = bit; m_eit = eit;
31 BT::loadBody(); 32 BT::loadBody();
32 } 33 }
33 }; 34 };
34 void load(istream& hs,istream& bs,int mask=0) { 35 void load(istream& hs,istream& bs,int mask=0) {
35 IParser prs(*this); 36 IParser prs(*this);
36 prs.iMask(mask); 37 prs.iMask(mask);
37 prs.loadHeader(it_type(hs),it_type()); 38 prs.loadHeader(it_type(hs),it_type());
38 prs.loadBody(it_type(bs),it_type()); 39 prs.loadBody(it_type(bs),it_type());
39 } 40 }
40 }; 41 };
41#endif /* HAVE_MIMETIC */ 42#endif /* HAVE_MIMETIC */
42 43
43 static string empty_string; 44 static string empty_string;
44 45
45 cgi_gateway::basic_file_t::~basic_file_t() { } 46 cgi_gateway::basic_file_t::~basic_file_t() { }
46 47
47 class string_file_t : public cgi_gateway::basic_file_t { 48 class string_file_t : public cgi_gateway::basic_file_t {
48 public: 49 public:
49 string _file_name; 50 string _file_name;
50 string _content_type; 51 string _content_type;
51 stringstream _content; 52 stringstream _content;
52 53
53 string_file_t(const string& fn,const string& ct,const string& s) 54 string_file_t(const string& fn,const string& ct,const string& s)
54 : _file_name(fn), _content_type(ct), _content(s,ios::in) { } 55 : _file_name(fn), _content_type(ct), _content(s,ios::in) { }
55 const string& filename() const { return _file_name; } 56 const string& filename() const { return _file_name; }
56 const string& content_type() const { return _content_type; } 57 const string& content_type() const { return _content_type; }
57 istream& content() { return _content; } 58 istream& content() { return _content; }
58 }; 59 };
59 60
60 cgi_gateway::cgi_gateway(cgi_interface& ci,bool parsebody) 61 cgi_gateway::cgi_gateway(cgi_interface& ci,bool parsebody)
61 : iface(ci), b_parsed_content(false) { 62 : iface(ci), b_parsed_content(false) {
62 // Fetch GET content 63 // Fetch GET content
63 try { 64 try {
64 string qs = get_meta("QUERY_STRING"); 65 string qs = get_meta("QUERY_STRING");
65 parse_query(qs,get); 66 parse_query(qs,get);
66 }catch(exception_notfound& enf) { } 67 }catch(exception_notfound& enf) { }
67 if(parsebody) 68 if(parsebody)
68 parse_request_body(); 69 parse_request_body();
69 // Parse cookies 70 // Parse cookies
70 try { 71 try {
71 cookies.parse_cookies(get_meta("HTTP_COOKIE")); 72 cookies.parse_cookies(get_meta("HTTP_COOKIE"));
72 }catch(exception_notfound& enf) { } 73 }catch(exception_notfound& enf) { }
73 } 74 }
74 75
75 cgi_gateway::~cgi_gateway() throw() { 76 cgi_gateway::~cgi_gateway() throw() {
76 for(files_t::iterator i=files.begin();i!=files.end();++i) 77 for(files_t::iterator i=files.begin();i!=files.end();++i)
77 delete i->second; 78 delete i->second;
78 files.clear(); 79 files.clear();
79 } 80 }
80 81
81 void cgi_gateway::parse_request_body() { 82 void cgi_gateway::parse_request_body() {
82 if(b_parsed_content) 83 if(b_parsed_content)
83 throw konforka::exception(CODEPOINT,"request body is already parsed"); 84 throw konforka::exception(CODEPOINT,"request body is already parsed");
84 // Fetch POST content 85 // Fetch POST content
85 if(!strncasecmp( 86 if(!strncasecmp(
86 content_type().c_str(), 87 content_type().c_str(),
87 "application/x-www-form-urlencoded", 88 "application/x-www-form-urlencoded",
88 sizeof("application/x-www-form-urlencoded")-1) ) { 89 sizeof("application/x-www-form-urlencoded")-1) ) {
89 unsigned long cl = content_length(); 90 unsigned long cl = content_length();
90 if(cl) { 91 if(cl) {
91 char * tmp = new char[cl]; 92 char * tmp = new char[cl];
92 iface.in().read(tmp,cl); 93 iface.in().read(tmp,cl);
93 string qs(tmp,cl); 94 string qs(tmp,cl);
94 delete tmp; 95 delete tmp;
95 parse_query(qs,post); 96 parse_query(qs,post);
96 } 97 }
97 b_parsed_content = true; 98 b_parsed_content = true;
98 } 99 }
99#ifdef HAVE_MIMETIC 100#ifdef HAVE_MIMETIC
100 else if(!strncasecmp( 101 else if(!strncasecmp(
101 content_type().c_str(), 102 content_type().c_str(),
102 "multipart/form-data", 103 "multipart/form-data",
103 sizeof("multipart/form-data")-1) ) { 104 sizeof("multipart/form-data")-1) ) {
104 stringstream h; 105 stringstream h;
105 h 106 h
106 << "Content-Type: " << content_type() << "\r\n" 107 << "Content-Type: " << content_type() << "\r\n"
107 << "Content-Length: " << content_length() << "\r\n\n"; 108 << "Content-Length: " << content_length() << "\r\n\n";
108 TornMimeEntity me; 109 TornMimeEntity me;
109 me.load(h,iface.in(),0); 110 me.load(h,iface.in(),0);
110 mimetic::MimeEntityList& parts = me.body().parts(); 111 mimetic::MimeEntityList& parts = me.body().parts();
111 for(mimetic::MimeEntityList::iterator i=parts.begin();i!=parts.end();++i) { 112 for(mimetic::MimeEntityList::iterator i=parts.begin();i!=parts.end();++i) {
112 MimeEntity *p = *i; 113 MimeEntity *p = *i;
113 const mimetic::ContentDisposition& cd = p->header().contentDisposition(); 114 const mimetic::ContentDisposition& cd = p->header().contentDisposition();
114 string n = cd.param("name"); 115 string n = cd.param("name");
115 string fn = cd.param("filename"); 116 string fn = cd.param("filename");
116 if(fn.empty()) { 117 if(fn.empty()) {
117 post.insert(params_t::value_type(n,p->body())); 118 post.insert(params_t::value_type(n,p->body()));
118 }else{ 119 }else{
119 const mimetic::ContentType& ct = p->header().contentType(); 120 const mimetic::ContentType& ct = p->header().contentType();
120 files.insert(files_t::value_type(n,new string_file_t(fn,ct.str(),p->body()))); 121 files.insert(files_t::value_type(n,new string_file_t(fn,ct.str(),p->body())));
121 } 122 }
122 } 123 }
123 b_parsed_content = true; 124 b_parsed_content = true;
124 } 125 }
125#endif /* HAVE_MIMETIC */ 126#endif /* HAVE_MIMETIC */
126 } 127 }
127 128
128 bool cgi_gateway::has_GET(const string& n) const { 129 bool cgi_gateway::has_GET(const string& n) const {
129 return get.find(n) != get.end(); 130 return get.find(n) != get.end();
130 } 131 }
131 const string& cgi_gateway::get_GET(const string& n) const { 132 const string& cgi_gateway::get_GET(const string& n) const {
132 params_t::const_iterator i = get.find(n); 133 params_t::const_iterator i = get.find(n);
133 if(i==get.end()) 134 if(i==get.end())
134 throw exception_notfound(CODEPOINT,"no such parameter"); 135 throw exception_notfound(CODEPOINT,"no such parameter");
135 return i->second; 136 return i->second;
136 } 137 }
137 bool cgi_gateway::has_POST(const string& n) const { 138 bool cgi_gateway::has_POST(const string& n) const {
138 return post.find(n) != post.end(); 139 return post.find(n) != post.end();
139 } 140 }
140 const string& cgi_gateway::get_POST(const string& n) const { 141 const string& cgi_gateway::get_POST(const string& n) const {
141 params_t::const_iterator i = post.find(n); 142 params_t::const_iterator i = post.find(n);
142 if(i==post.end()) 143 if(i==post.end())
143 throw exception_notfound(CODEPOINT,"no such parameter"); 144 throw exception_notfound(CODEPOINT,"no such parameter");
144 return i->second; 145 return i->second;
145 } 146 }
146 bool cgi_gateway::has_param(const string& n) const { 147 bool cgi_gateway::has_param(const string& n) const {
147 return has_GET(n) || has_POST(n); 148 return has_GET(n) || has_POST(n);
148 } 149 }
149 const string& cgi_gateway::get_param(const string& n) const { 150 const string& cgi_gateway::get_param(const string& n) const {
150 params_t::const_iterator i = get.find(n); 151 params_t::const_iterator i = get.find(n);
151 if(i!=get.end()) 152 if(i!=get.end())
152 return i->second; 153 return i->second;
153 i = post.find(n); 154 i = post.find(n);
154 if(i!=post.end()) 155 if(i!=post.end())
155 return i->second; 156 return i->second;
156 throw exception_notfound(CODEPOINT,"no such parameter"); 157 throw exception_notfound(CODEPOINT,"no such parameter");
157 } 158 }
158 bool cgi_gateway::has_file(const string& n) const { 159 bool cgi_gateway::has_file(const string& n) const {
159 return files.find(n) != files.end(); 160 return files.find(n) != files.end();
160 } 161 }
161 const cgi_gateway::file_t cgi_gateway::get_file(const string& n) const { 162 const cgi_gateway::file_t cgi_gateway::get_file(const string& n) const {
162 files_t::const_iterator i = files.find(n); 163 files_t::const_iterator i = files.find(n);
163 if(i==files.end()) 164 if(i==files.end())
164 throw exception_notfound(CODEPOINT,"no such parameter"); 165 throw exception_notfound(CODEPOINT,"no such parameter");
165 return i->second; 166 return i->second;
166 } 167 }
167 cgi_gateway::file_t cgi_gateway::get_file(const string& n) { 168 cgi_gateway::file_t cgi_gateway::get_file(const string& n) {
168 files_t::const_iterator i = files.find(n); 169 files_t::const_iterator i = files.find(n);
169 if(i==files.end()) 170 if(i==files.end())
170 throw exception_notfound(CODEPOINT,"no such parameter"); 171 throw exception_notfound(CODEPOINT,"no such parameter");
171 return i->second; 172 return i->second;
172 } 173 }
173 174
174 /* 175 /*
175 * deprecated stuff. 176 * deprecated stuff.
176 */ 177 */
177 const string& cgi_gateway::get_content_type() const { 178 const string& cgi_gateway::get_content_type() const {
178 if(!has_meta("CONTENT_TYPE")) 179 if(!has_meta("CONTENT_TYPE"))
179 return empty_string; 180 return empty_string;
180 return get_meta("CONTENT_TYPE"); 181 return get_meta("CONTENT_TYPE");
181 } 182 }
182 unsigned long cgi_gateway::get_content_length() const { 183 unsigned long cgi_gateway::get_content_length() const {
183 if(!has_meta("CONTENT_LENGTH")) 184 if(!has_meta("CONTENT_LENGTH"))
184 return 0; 185 return 0;
185 string cl = get_meta("CONTENT_LENGTH"); 186 string cl = get_meta("CONTENT_LENGTH");
186 return strtol(cl.c_str(),NULL,10); 187 return strtol(cl.c_str(),NULL,10);
187 } 188 }
188 /* 189 /*
189 * 190 *
190 */ 191 */
191 192
192 const string& cgi_gateway::http_request_header(const string& hn) const { 193 const string& cgi_gateway::http_request_header(const string& hn) const {
193 string mvn = "HTTP_"; 194 string mvn = "HTTP_";
194 for(const char* p=hn.c_str();*p;p++) { 195 for(const char* p=hn.c_str();*p;p++) {
195 if(*p=='-') 196 if(*p=='-')
diff --git a/src/fastcgi.cc b/src/fastcgi.cc
index 8b7668c..5a6c081 100644
--- a/src/fastcgi.cc
+++ b/src/fastcgi.cc
@@ -1,69 +1,70 @@
1#include <unistd.h> 1#include <unistd.h>
2#include <sys/types.h> 2#include <sys/types.h>
3#include <sys/stat.h> 3#include <sys/stat.h>
4#include <cstring>
4#include "kingate/fastcgi.h" 5#include "kingate/fastcgi.h"
5#include "kingate/exception.h" 6#include "kingate/exception.h"
6 7
7namespace kingate { 8namespace kingate {
8 9
9 bool fcgi_socket::_initialized = false; 10 bool fcgi_socket::_initialized = false;
10 11
11 fcgi_socket::fcgi_socket(const char *s,int bl) 12 fcgi_socket::fcgi_socket(const char *s,int bl)
12 : sock(-1) { 13 : sock(-1) {
13 if(!_initialized) { 14 if(!_initialized) {
14 if( FCGX_Init() ) 15 if( FCGX_Init() )
15 throw exception(CODEPOINT,"failed to FCGX_Init()"); 16 throw exception(CODEPOINT,"failed to FCGX_Init()");
16 _initialized = true; 17 _initialized = true;
17 } 18 }
18 sock = FCGX_OpenSocket(s,bl); 19 sock = FCGX_OpenSocket(s,bl);
19 if(sock<0) 20 if(sock<0)
20 throw exception(CODEPOINT,"failed to FCGX_OpenSocket("); 21 throw exception(CODEPOINT,"failed to FCGX_OpenSocket(");
21 // TODO: check if there is a ':', not if it starts with ':' 22 // TODO: check if there is a ':', not if it starts with ':'
22 if(*s != ':') 23 if(*s != ':')
23 if(chmod(s,0777)) // XXX: configurable. 24 if(chmod(s,0777)) // XXX: configurable.
24 throw exception(CODEPOINT,"failed to chmod()"); 25 throw exception(CODEPOINT,"failed to chmod()");
25 } 26 }
26 fcgi_socket::fcgi_socket(int s) 27 fcgi_socket::fcgi_socket(int s)
27 : sock(0) { 28 : sock(0) {
28 if(!_initialized) { 29 if(!_initialized) {
29 if( FCGX_Init() ) 30 if( FCGX_Init() )
30 throw exception(CODEPOINT,"failed to FCGX_Init()"); 31 throw exception(CODEPOINT,"failed to FCGX_Init()");
31 _initialized = true; 32 _initialized = true;
32 } 33 }
33 } 34 }
34 fcgi_socket::~fcgi_socket() { 35 fcgi_socket::~fcgi_socket() {
35 if(sock>=0) 36 if(sock>=0)
36 close(sock); 37 close(sock);
37 } 38 }
38 39
39 fcgi_interface::fcgi_interface(fcgi_socket& s,int f) 40 fcgi_interface::fcgi_interface(fcgi_socket& s,int f)
40 : sbin(buf_sbin,sizeof(buf_sbin)), 41 : sbin(buf_sbin,sizeof(buf_sbin)),
41 sbout(buf_sbout,sizeof(buf_sbout)), 42 sbout(buf_sbout,sizeof(buf_sbout)),
42 sberr(buf_sberr,sizeof(buf_sberr)), 43 sberr(buf_sberr,sizeof(buf_sberr)),
43 sin(&sbin), sout(&sbout), serr(&sberr) { 44 sin(&sbin), sout(&sbout), serr(&sberr) {
44 if( FCGX_InitRequest(&request,s.sock,f) ) 45 if( FCGX_InitRequest(&request,s.sock,f) )
45 throw exception(CODEPOINT,"failed to FCGX_InitRequest()"); 46 throw exception(CODEPOINT,"failed to FCGX_InitRequest()");
46 if( FCGX_Accept_r(&request) ) 47 if( FCGX_Accept_r(&request) )
47 throw exception(CODEPOINT,"failed to FCGX_Accept_r()"); 48 throw exception(CODEPOINT,"failed to FCGX_Accept_r()");
48 sbin.attach(request.in); 49 sbin.attach(request.in);
49 sbout.attach(request.out); 50 sbout.attach(request.out);
50 sberr.attach(request.err); 51 sberr.attach(request.err);
51 for(char **p = request.envp; *p; p++) { 52 for(char **p = request.envp; *p; p++) {
52 const char *e = strchr(*p,'='); 53 const char *e = strchr(*p,'=');
53 if(!e){ 54 if(!e){
54 // XXX: check if we have it already? 55 // XXX: check if we have it already?
55 metavars[*p] = string(0); 56 metavars[*p] = string(0);
56 }else{ 57 }else{
57 int l = e-*p; e++; 58 int l = e-*p; e++;
58 // XXX: check if we have it already? 59 // XXX: check if we have it already?
59 metavars[string(*p,l)]=e; 60 metavars[string(*p,l)]=e;
60 } 61 }
61 } 62 }
62 } 63 }
63 fcgi_interface::~fcgi_interface() { 64 fcgi_interface::~fcgi_interface() {
64 sout.flush(); 65 sout.flush();
65 serr.flush(); 66 serr.flush();
66 FCGX_Finish_r(&request); 67 FCGX_Finish_r(&request);
67 } 68 }
68 69
69} 70}
diff --git a/src/plaincgi.cc b/src/plaincgi.cc
index 1cb7dc6..3a82d33 100644
--- a/src/plaincgi.cc
+++ b/src/plaincgi.cc
@@ -1,32 +1,33 @@
1#include <unistd.h> 1#include <unistd.h>
2#include <sys/types.h> 2#include <sys/types.h>
3#include <sys/stat.h> 3#include <sys/stat.h>
4#include <cstring>
4#include "kingate/plaincgi.h" 5#include "kingate/plaincgi.h"
5#include "kingate/exception.h" 6#include "kingate/exception.h"
6#include "config.h" 7#include "config.h"
7 8
8#if !HAVE_DECL_ENVIRON 9#if !HAVE_DECL_ENVIRON
9extern char **environ; 10extern char **environ;
10#endif /* HAVE_DECL_ENVIRON */ 11#endif /* HAVE_DECL_ENVIRON */
11 12
12namespace kingate { 13namespace kingate {
13 14
14 plaincgi_interface::plaincgi_interface() { 15 plaincgi_interface::plaincgi_interface() {
15 for(char **p = environ; *p; p++) { 16 for(char **p = environ; *p; p++) {
16 const char *e = strchr(*p,'='); 17 const char *e = strchr(*p,'=');
17 if(!e){ 18 if(!e){
18 // XXX: check if we have it already? 19 // XXX: check if we have it already?
19 metavars[*p] = string(0); 20 metavars[*p] = string(0);
20 }else{ 21 }else{
21 int l = e-*p; e++; 22 int l = e-*p; e++;
22 // XXX: check if we have it already? 23 // XXX: check if we have it already?
23 metavars[string(*p,l)]=e; 24 metavars[string(*p,l)]=e;
24 } 25 }
25 } 26 }
26 } 27 }
27 plaincgi_interface::~plaincgi_interface() { 28 plaincgi_interface::~plaincgi_interface() {
28 cout.flush(); 29 cout.flush();
29 cerr.flush(); 30 cerr.flush();
30 } 31 }
31 32
32} 33}
diff --git a/src/util.cc b/src/util.cc
index 48e486a..76e684f 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -1,106 +1,107 @@
1#include <cstring>
1#include "kingate/util.h" 2#include "kingate/util.h"
2#include "kingate/exception.h" 3#include "kingate/exception.h"
3 4
4namespace kingate { 5namespace kingate {
5 6
6 static const char *safeChars = 7 static const char *safeChars =
7 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 8 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
8 "abcdefghijklmnopqrstuvwxyz" 9 "abcdefghijklmnopqrstuvwxyz"
9 "0123456789" 10 "0123456789"
10 "_-" ; 11 "_-" ;
11 12
12 string url_encode(const string& str) { 13 string url_encode(const string& str) {
13 string rv = str; 14 string rv = str;
14 string::size_type screwed = 0; 15 string::size_type screwed = 0;
15 for(;;) { 16 for(;;) {
16 screwed = rv.find_first_not_of(safeChars,screwed); 17 screwed = rv.find_first_not_of(safeChars,screwed);
17 if(screwed == string::npos) 18 if(screwed == string::npos)
18 break; 19 break;
19 while(screwed<rv.length() && !strchr(safeChars,rv.at(screwed))) { 20 while(screwed<rv.length() && !strchr(safeChars,rv.at(screwed))) {
20 char danger = rv.at(screwed); 21 char danger = rv.at(screwed);
21 if(danger==' ') { 22 if(danger==' ') {
22 rv.replace(screwed++,1,1,'+'); 23 rv.replace(screwed++,1,1,'+');
23 }else{ 24 }else{
24 static char tmp[4] = {'%',0,0,0}; 25 static char tmp[4] = {'%',0,0,0};
25 snprintf(&tmp[1],3,"%02X",0xFF&(int)danger); 26 snprintf(&tmp[1],3,"%02X",0xFF&(int)danger);
26 rv.replace(screwed,1,tmp,3); 27 rv.replace(screwed,1,tmp,3);
27 screwed+=3; 28 screwed+=3;
28 } 29 }
29 } 30 }
30 } 31 }
31 return rv; 32 return rv;
32 } 33 }
33 string url_decode(const string& str) { 34 string url_decode(const string& str) {
34 string rv = str; 35 string rv = str;
35 string::size_type unscrewed = 0; 36 string::size_type unscrewed = 0;
36 for(;;) { 37 for(;;) {
37 unscrewed = rv.find_first_of("%+",unscrewed); 38 unscrewed = rv.find_first_of("%+",unscrewed);
38 if(unscrewed == string::npos) 39 if(unscrewed == string::npos)
39 break; 40 break;
40 if(rv.at(unscrewed)=='+') { 41 if(rv.at(unscrewed)=='+') {
41 rv.replace(unscrewed++,1,1,' '); 42 rv.replace(unscrewed++,1,1,' ');
42 }else{ 43 }else{
43 if((rv.length()-unscrewed)<3) 44 if((rv.length()-unscrewed)<3)
44 throw exception(CODEPOINT,"incorrectly escaped string"); 45 throw exception(CODEPOINT,"incorrectly escaped string");
45 // XXX: ensure it's hex? 46 // XXX: ensure it's hex?
46 int danger = strtol(rv.substr(unscrewed+1,2).c_str(),NULL,16); 47 int danger = strtol(rv.substr(unscrewed+1,2).c_str(),NULL,16);
47 rv.replace(unscrewed,3,1,danger); 48 rv.replace(unscrewed,3,1,danger);
48 unscrewed++; 49 unscrewed++;
49 } 50 }
50 } 51 }
51 return rv; 52 return rv;
52 } 53 }
53 54
54 /* 55 /*
55 * RFC 2616: 56 * RFC 2616:
56 * 57 *
57 * separators = "(" | ")" | "<" | ">" | "@" 58 * separators = "(" | ")" | "<" | ">" | "@"
58 * | "," | ";" | ":" | "\" | <"> 59 * | "," | ";" | ":" | "\" | <">
59 * | "/" | "[" | "]" | "?" | "=" 60 * | "/" | "[" | "]" | "?" | "="
60 * | "{" | "}" | SP | HT 61 * | "{" | "}" | SP | HT
61 */ 62 */
62 63
63 /* 64 /*
64 * RFC 2616: 65 * RFC 2616:
65 * 66 *
66 * token = 1*<any CHAR except CTLs or separators> 67 * token = 1*<any CHAR except CTLs or separators>
67 */ 68 */
68 69
69 static const char *quotible_chars = 70 static const char *quotible_chars =
70 "\001\002\003\004\005\006\007\010" 71 "\001\002\003\004\005\006\007\010"
71 "\011\012\013\014\015\016\017\020" 72 "\011\012\013\014\015\016\017\020"
72 "\021\022\023\024\025\026\027\030" 73 "\021\022\023\024\025\026\027\030"
73 "\031\032\033\034\035\036\037\040" 74 "\031\032\033\034\035\036\037\040"
74 "()<>@,;:\\\"/[]?={}" /* separator chars (except for SP and HT mentioned elsewhere */ 75 "()<>@,;:\\\"/[]?={}" /* separator chars (except for SP and HT mentioned elsewhere */
75 "\177" 76 "\177"
76 ; 77 ;
77 78
78 /* 79 /*
79 * RFC 2616: 80 * RFC 2616:
80 * 81 *
81 * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> ) 82 * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
82 * qdtext = <any TEXT except <">> 83 * qdtext = <any TEXT except <">>
83 * 84 *
84 * The backslash character ("\") MAY be used as a single-character 85 * The backslash character ("\") MAY be used as a single-character
85 * quoting mechanism only within quoted-string and comment constructs. 86 * quoting mechanism only within quoted-string and comment constructs.
86 * 87 *
87 * quoted-pair = "\" CHAR 88 * quoted-pair = "\" CHAR
88 */ 89 */
89 90
90 string http_quoted_string(const string& str) { 91 string http_quoted_string(const string& str) {
91 string rv = str; 92 string rv = str;
92 string::size_type sp=0; 93 string::size_type sp=0;
93 for(string::size_type q=rv.find('"');(q=rv.find('"',q))!=string::npos;q+=2) 94 for(string::size_type q=rv.find('"');(q=rv.find('"',q))!=string::npos;q+=2)
94 rv.insert(q,1,'\\'); 95 rv.insert(q,1,'\\');
95 rv.insert(0,1,'"'); 96 rv.insert(0,1,'"');
96 rv += '"'; 97 rv += '"';
97 return rv; 98 return rv;
98 } 99 }
99 100
100 string http_quote(const string& str) { 101 string http_quote(const string& str) {
101 if(str.find_first_of(quotible_chars)==string::npos) 102 if(str.find_first_of(quotible_chars)==string::npos)
102 return str; 103 return str;
103 return http_quoted_string(str); 104 return http_quoted_string(str);
104 } 105 }
105 106
106} 107}