author | Michael Krelin <hacker@klever.net> | 2008-04-06 19:26:50 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2008-04-06 19:26:50 (UTC) |
commit | aa3a6821f6aaaf4ae63bafbbc76da5f414a75fd4 (patch) (unidiff) | |
tree | c64231565e123d678850a7b0560b348ee82b2dcc | |
parent | 752e484cd2fc239bc582a88fe7d62a225880ee3b (diff) | |
download | libopkele-aa3a6821f6aaaf4ae63bafbbc76da5f414a75fd4.zip libopkele-aa3a6821f6aaaf4ae63bafbbc76da5f414a75fd4.tar.gz libopkele-aa3a6821f6aaaf4ae63bafbbc76da5f414a75fd4.tar.bz2 |
fix for discovery failing on some entities coming before the tag of interest
One of the numerous opportunities to express my gratitude by means of commit
message to Joseph Smarr of Plaxo for spotting it. Thanks, Joseph!
Signed-off-by: Michael Krelin <hacker@klever.net>
-rw-r--r-- | lib/discovery.cc | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/lib/discovery.cc b/lib/discovery.cc index c118c80..3b90977 100644 --- a/lib/discovery.cc +++ b/lib/discovery.cc | |||
@@ -1,582 +1,583 @@ | |||
1 | #include <list> | 1 | #include <list> |
2 | #include <opkele/curl.h> | 2 | #include <opkele/curl.h> |
3 | #include <opkele/expat.h> | 3 | #include <opkele/expat.h> |
4 | #include <opkele/uris.h> | 4 | #include <opkele/uris.h> |
5 | #include <opkele/discovery.h> | 5 | #include <opkele/discovery.h> |
6 | #include <opkele/exception.h> | 6 | #include <opkele/exception.h> |
7 | #include <opkele/util.h> | 7 | #include <opkele/util.h> |
8 | #include <opkele/tidy.h> | 8 | #include <opkele/tidy.h> |
9 | #include <opkele/data.h> | 9 | #include <opkele/data.h> |
10 | #include <opkele/debug.h> | 10 | #include <opkele/debug.h> |
11 | 11 | ||
12 | #include "config.h" | 12 | #include "config.h" |
13 | 13 | ||
14 | #define XRDS_HEADER "X-XRDS-Location" | 14 | #define XRDS_HEADER "X-XRDS-Location" |
15 | #define CT_HEADER "Content-Type" | 15 | #define CT_HEADER "Content-Type" |
16 | 16 | ||
17 | namespace opkele { | 17 | namespace opkele { |
18 | using std::list; | 18 | using std::list; |
19 | using xrd::XRD_t; | 19 | using xrd::XRD_t; |
20 | using xrd::service_t; | 20 | using xrd::service_t; |
21 | 21 | ||
22 | /* TODO: the whole discovery thing needs cleanup and optimization due to | 22 | /* TODO: the whole discovery thing needs cleanup and optimization due to |
23 | * many changes of concept. */ | 23 | * many changes of concept. */ |
24 | 24 | ||
25 | static const size_t max_html = 16384; | 25 | static const size_t max_html = 16384; |
26 | 26 | ||
27 | static const struct service_type_t { | 27 | static const struct service_type_t { |
28 | const char *uri; | 28 | const char *uri; |
29 | const char *forceid; | 29 | const char *forceid; |
30 | } op_service_types[] = { | 30 | } op_service_types[] = { |
31 | { STURI_OPENID20_OP, IDURI_SELECT20 }, | 31 | { STURI_OPENID20_OP, IDURI_SELECT20 }, |
32 | { STURI_OPENID20, 0 }, | 32 | { STURI_OPENID20, 0 }, |
33 | { STURI_OPENID11, 0 }, | 33 | { STURI_OPENID11, 0 }, |
34 | { STURI_OPENID10, 0 } | 34 | { STURI_OPENID10, 0 } |
35 | }; | 35 | }; |
36 | enum { | 36 | enum { |
37 | st_index_1 = 2, st_index_2 = 1 | 37 | st_index_1 = 2, st_index_2 = 1 |
38 | }; | 38 | }; |
39 | 39 | ||
40 | 40 | ||
41 | static inline bool is_qelement(const XML_Char *n,const char *qen) { | 41 | static inline bool is_qelement(const XML_Char *n,const char *qen) { |
42 | return !strcasecmp(n,qen); | 42 | return !strcasecmp(n,qen); |
43 | } | 43 | } |
44 | static inline bool is_element(const XML_Char *n,const char *en) { | 44 | static inline bool is_element(const XML_Char *n,const char *en) { |
45 | if(!strcasecmp(n,en)) return true; | 45 | if(!strcasecmp(n,en)) return true; |
46 | int nl = strlen(n), enl = strlen(en); | 46 | int nl = strlen(n), enl = strlen(en); |
47 | if( (nl>=(enl+1)) && n[nl-enl-1]=='\t' | 47 | if( (nl>=(enl+1)) && n[nl-enl-1]=='\t' |
48 | && !strcasecmp(&n[nl-enl],en) ) | 48 | && !strcasecmp(&n[nl-enl],en) ) |
49 | return true; | 49 | return true; |
50 | return false; | 50 | return false; |
51 | } | 51 | } |
52 | 52 | ||
53 | static long element_priority(const XML_Char **a) { | 53 | static long element_priority(const XML_Char **a) { |
54 | for(;*a;++a) | 54 | for(;*a;++a) |
55 | if(!strcasecmp(*(a++),"priority")) { | 55 | if(!strcasecmp(*(a++),"priority")) { |
56 | long rv; | 56 | long rv; |
57 | return (sscanf(*a,"%ld",&rv)==1)?rv:-1; | 57 | return (sscanf(*a,"%ld",&rv)==1)?rv:-1; |
58 | } | 58 | } |
59 | return -1; | 59 | return -1; |
60 | } | 60 | } |
61 | /* TODO: ideally all attributes should be | 61 | /* TODO: ideally all attributes should be |
62 | * retrieved in one run */ | 62 | * retrieved in one run */ |
63 | static const char *element_attr(const XML_Char **a, const char *at) { | 63 | static const char *element_attr(const XML_Char **a, const char *at) { |
64 | for(;*a;++a) | 64 | for(;*a;++a) |
65 | if(!strcasecmp(*(a++),at)) { | 65 | if(!strcasecmp(*(a++),at)) { |
66 | return *a; | 66 | return *a; |
67 | } | 67 | } |
68 | return 0; | 68 | return 0; |
69 | } | 69 | } |
70 | 70 | ||
71 | class idigger_t : public util::curl_t, public util::expat_t { | 71 | class idigger_t : public util::curl_t, public util::expat_t { |
72 | public: | 72 | public: |
73 | string xri_proxy; | 73 | string xri_proxy; |
74 | 74 | ||
75 | enum { | 75 | enum { |
76 | xmode_html = 1, xmode_xrd = 2, xmode_cid = 4, | 76 | xmode_html = 1, xmode_xrd = 2, xmode_cid = 4, |
77 | xmode_noredirs = 8 | 77 | xmode_noredirs = 8 |
78 | }; | 78 | }; |
79 | int xmode; | 79 | int xmode; |
80 | 80 | ||
81 | string xrds_location; | 81 | string xrds_location; |
82 | string http_content_type; | 82 | string http_content_type; |
83 | service_t html_openid1; | 83 | service_t html_openid1; |
84 | service_t html_openid2; | 84 | service_t html_openid2; |
85 | string cdata_buf; | 85 | string cdata_buf; |
86 | long status_code; | 86 | long status_code; |
87 | string status_string; | 87 | string status_string; |
88 | 88 | ||
89 | typedef list<string> pt_stack_t; | 89 | typedef list<string> pt_stack_t; |
90 | pt_stack_t pt_stack; | 90 | pt_stack_t pt_stack; |
91 | int skipping; | 91 | int skipping; |
92 | bool parser_choked; | 92 | bool parser_choked; |
93 | string save_html; | 93 | string save_html; |
94 | 94 | ||
95 | XRD_t *xrd; | 95 | XRD_t *xrd; |
96 | service_t *xrd_service; | 96 | service_t *xrd_service; |
97 | string* cdata; | 97 | string* cdata; |
98 | 98 | ||
99 | idigger_t() | 99 | idigger_t() |
100 | : util::curl_t(easy_init()), | 100 | : util::curl_t(easy_init()), |
101 | util::expat_t(0), | 101 | util::expat_t(0), |
102 | xri_proxy(XRI_PROXY_URL) { | 102 | xri_proxy(XRI_PROXY_URL) { |
103 | CURLcode r; | 103 | CURLcode r; |
104 | (r=misc_sets()) | 104 | (r=misc_sets()) |
105 | || (r=set_write()) | 105 | || (r=set_write()) |
106 | || (r=set_header()) | 106 | || (r=set_header()) |
107 | ; | 107 | ; |
108 | if(r) | 108 | if(r) |
109 | throw exception_curl(OPKELE_CP_ "failed to set curly options",r); | 109 | throw exception_curl(OPKELE_CP_ "failed to set curly options",r); |
110 | } | 110 | } |
111 | ~idigger_t() throw() { } | 111 | ~idigger_t() throw() { } |
112 | 112 | ||
113 | void yadiscover(endpoint_discovery_iterator oi,const string& yurl,const char **types,bool redirs) { | 113 | void yadiscover(endpoint_discovery_iterator oi,const string& yurl,const char **types,bool redirs) { |
114 | idiscovery_t idis; | 114 | idiscovery_t idis; |
115 | idis.xri_identity = false; | 115 | idis.xri_identity = false; |
116 | discover_at(idis,yurl,xmode_html|xmode_xrd|(redirs?0:xmode_noredirs)); | 116 | discover_at(idis,yurl,xmode_html|xmode_xrd|(redirs?0:xmode_noredirs)); |
117 | if(!xrds_location.empty()) { | 117 | if(!xrds_location.empty()) { |
118 | idis.clear(); | 118 | idis.clear(); |
119 | discover_at(idis,xrds_location,xmode_xrd); | 119 | discover_at(idis,xrds_location,xmode_xrd); |
120 | } | 120 | } |
121 | idis.normalized_id = idis.canonicalized_id = yurl; | 121 | idis.normalized_id = idis.canonicalized_id = yurl; |
122 | service_type_t st; | 122 | service_type_t st; |
123 | for(st.uri=*types;*types;st.uri=*(++types)) | 123 | for(st.uri=*types;*types;st.uri=*(++types)) |
124 | queue_endpoints(oi,idis,&st); | 124 | queue_endpoints(oi,idis,&st); |
125 | } | 125 | } |
126 | 126 | ||
127 | string discover(endpoint_discovery_iterator& oi,const string& identity) { | 127 | string discover(endpoint_discovery_iterator& oi,const string& identity) { |
128 | string rv; | 128 | string rv; |
129 | idiscovery_t idis; | 129 | idiscovery_t idis; |
130 | string::size_type fsc = identity.find_first_not_of(data::_whitespace_chars); | 130 | string::size_type fsc = identity.find_first_not_of(data::_whitespace_chars); |
131 | if(fsc==string::npos) | 131 | if(fsc==string::npos) |
132 | throw bad_input(OPKELE_CP_ "whitespace-only identity"); | 132 | throw bad_input(OPKELE_CP_ "whitespace-only identity"); |
133 | string::size_type lsc = identity.find_last_not_of(data::_whitespace_chars); | 133 | string::size_type lsc = identity.find_last_not_of(data::_whitespace_chars); |
134 | assert(lsc!=string::npos); | 134 | assert(lsc!=string::npos); |
135 | if(!strncasecmp(identity.c_str()+fsc,"xri://",sizeof("xri://")-1)) | 135 | if(!strncasecmp(identity.c_str()+fsc,"xri://",sizeof("xri://")-1)) |
136 | fsc += sizeof("xri://")-1; | 136 | fsc += sizeof("xri://")-1; |
137 | if((fsc+1)>=lsc) | 137 | if((fsc+1)>=lsc) |
138 | throw bad_input(OPKELE_CP_ "not a character of importance in identity"); | 138 | throw bad_input(OPKELE_CP_ "not a character of importance in identity"); |
139 | string id(identity,fsc,lsc-fsc+1); | 139 | string id(identity,fsc,lsc-fsc+1); |
140 | idis.clear(); | 140 | idis.clear(); |
141 | if(strchr(data::_iname_leaders,id[0])) { | 141 | if(strchr(data::_iname_leaders,id[0])) { |
142 | /* TODO: further normalize xri identity? Like folding case | 142 | /* TODO: further normalize xri identity? Like folding case |
143 | * or whatever... */ | 143 | * or whatever... */ |
144 | rv = id; | 144 | rv = id; |
145 | set<string> cids; | 145 | set<string> cids; |
146 | for(const struct service_type_t *st=op_service_types; | 146 | for(const struct service_type_t *st=op_service_types; |
147 | st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) { | 147 | st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) { |
148 | idis.clear(); | 148 | idis.clear(); |
149 | discover_at( idis, | 149 | discover_at( idis, |
150 | xri_proxy + util::url_encode(id)+ | 150 | xri_proxy + util::url_encode(id)+ |
151 | "?_xrd_t="+util::url_encode(st->uri)+ | 151 | "?_xrd_t="+util::url_encode(st->uri)+ |
152 | "&_xrd_r=application/xrd%2Bxml" | 152 | "&_xrd_r=application/xrd%2Bxml" |
153 | ";sep=true;refs=true", | 153 | ";sep=true;refs=true", |
154 | xmode_xrd ); | 154 | xmode_xrd ); |
155 | if(status_code==241) continue; | 155 | if(status_code==241) continue; |
156 | if(status_code!=100) | 156 | if(status_code!=100) |
157 | throw failed_xri_resolution(OPKELE_CP_ | 157 | throw failed_xri_resolution(OPKELE_CP_ |
158 | "XRI resolution failed with '"+status_string+"' message" | 158 | "XRI resolution failed with '"+status_string+"' message" |
159 | ", while looking for SEP with type '"+st->uri+"'", status_code); | 159 | ", while looking for SEP with type '"+st->uri+"'", status_code); |
160 | if(idis.xrd.canonical_ids.empty()) | 160 | if(idis.xrd.canonical_ids.empty()) |
161 | throw opkele::failed_discovery(OPKELE_CP_ "No CanonicalID for XRI identity found"); | 161 | throw opkele::failed_discovery(OPKELE_CP_ "No CanonicalID for XRI identity found"); |
162 | string cid = idis.xrd.canonical_ids.begin()->second; | 162 | string cid = idis.xrd.canonical_ids.begin()->second; |
163 | if(cids.find(cid)==cids.end()) { | 163 | if(cids.find(cid)==cids.end()) { |
164 | cids.insert(cid); | 164 | cids.insert(cid); |
165 | idis.clear(); | 165 | idis.clear(); |
166 | discover_at( idis, | 166 | discover_at( idis, |
167 | xri_proxy + util::url_encode(id)+ | 167 | xri_proxy + util::url_encode(id)+ |
168 | "?_xrd_t="+util::url_encode(st->uri)+ | 168 | "?_xrd_t="+util::url_encode(st->uri)+ |
169 | "&_xrd_r=application/xrd%2Bxml" | 169 | "&_xrd_r=application/xrd%2Bxml" |
170 | ";sep=true;refs=true", | 170 | ";sep=true;refs=true", |
171 | xmode_xrd ); | 171 | xmode_xrd ); |
172 | if(status_code==241) continue; | 172 | if(status_code==241) continue; |
173 | if(status_code!=100) | 173 | if(status_code!=100) |
174 | throw failed_xri_resolution(OPKELE_CP_ | 174 | throw failed_xri_resolution(OPKELE_CP_ |
175 | "XRI resolution failed with '"+status_string+"' message" | 175 | "XRI resolution failed with '"+status_string+"' message" |
176 | ", while looking for SEP with type '"+st->uri+"'" | 176 | ", while looking for SEP with type '"+st->uri+"'" |
177 | " on canonical id", status_code); | 177 | " on canonical id", status_code); |
178 | } | 178 | } |
179 | idis.canonicalized_id = cid; | 179 | idis.canonicalized_id = cid; |
180 | idis.normalized_id = rv; idis.xri_identity = true; | 180 | idis.normalized_id = rv; idis.xri_identity = true; |
181 | queue_endpoints(oi,idis,st); | 181 | queue_endpoints(oi,idis,st); |
182 | } | 182 | } |
183 | }else{ | 183 | }else{ |
184 | idis.xri_identity = false; | 184 | idis.xri_identity = false; |
185 | if(id.find("://")==string::npos) | 185 | if(id.find("://")==string::npos) |
186 | id.insert(0,"http://"); | 186 | id.insert(0,"http://"); |
187 | string::size_type fp = id.find('#'); | 187 | string::size_type fp = id.find('#'); |
188 | if(fp!=string::npos) { | 188 | if(fp!=string::npos) { |
189 | string::size_type qp = id.find('?'); | 189 | string::size_type qp = id.find('?'); |
190 | if(qp==string::npos || qp<fp) | 190 | if(qp==string::npos || qp<fp) |
191 | id.erase(fp); | 191 | id.erase(fp); |
192 | else if(qp>fp) | 192 | else if(qp>fp) |
193 | id.erase(fp,qp-fp); | 193 | id.erase(fp,qp-fp); |
194 | } | 194 | } |
195 | rv = idis.normalized_id = util::rfc_3986_normalize_uri(id); | 195 | rv = idis.normalized_id = util::rfc_3986_normalize_uri(id); |
196 | discover_at(idis,id,xmode_html|xmode_xrd); | 196 | discover_at(idis,id,xmode_html|xmode_xrd); |
197 | const char * eu = 0; | 197 | const char * eu = 0; |
198 | CURLcode r = easy_getinfo(CURLINFO_EFFECTIVE_URL,&eu); | 198 | CURLcode r = easy_getinfo(CURLINFO_EFFECTIVE_URL,&eu); |
199 | if(r) | 199 | if(r) |
200 | throw exception_curl(OPKELE_CP_ "failed to get CURLINFO_EFFECTIVE_URL",r); | 200 | throw exception_curl(OPKELE_CP_ "failed to get CURLINFO_EFFECTIVE_URL",r); |
201 | string cid = util::strip_uri_fragment_part( idis.canonicalized_id = util::rfc_3986_normalize_uri(eu) ); | 201 | string cid = util::strip_uri_fragment_part( idis.canonicalized_id = util::rfc_3986_normalize_uri(eu) ); |
202 | if(xrds_location.empty()) { | 202 | if(xrds_location.empty()) { |
203 | if(idis.xrd.empty()) | 203 | if(idis.xrd.empty()) |
204 | html2xrd(oi,idis); | 204 | html2xrd(oi,idis); |
205 | else{ | 205 | else{ |
206 | for(const service_type_t *st=op_service_types; | 206 | for(const service_type_t *st=op_service_types; |
207 | st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) | 207 | st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) |
208 | queue_endpoints(oi,idis,st); | 208 | queue_endpoints(oi,idis,st); |
209 | } | 209 | } |
210 | }else{ | 210 | }else{ |
211 | idis.clear(); | 211 | idis.clear(); |
212 | idis.canonicalized_id = cid; | 212 | idis.canonicalized_id = cid; |
213 | discover_at(idis,xrds_location,xmode_xrd); | 213 | discover_at(idis,xrds_location,xmode_xrd); |
214 | if(idis.xrd.empty()) | 214 | if(idis.xrd.empty()) |
215 | html2xrd(oi,idis); | 215 | html2xrd(oi,idis); |
216 | else{ | 216 | else{ |
217 | for(const service_type_t *st=op_service_types; | 217 | for(const service_type_t *st=op_service_types; |
218 | st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) | 218 | st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) |
219 | queue_endpoints(oi,idis,st); | 219 | queue_endpoints(oi,idis,st); |
220 | } | 220 | } |
221 | } | 221 | } |
222 | } | 222 | } |
223 | return rv; | 223 | return rv; |
224 | } | 224 | } |
225 | 225 | ||
226 | void discover_at(idiscovery_t& idis,const string& url,int xm) { | 226 | void discover_at(idiscovery_t& idis,const string& url,int xm) { |
227 | CURLcode r = easy_setopt(CURLOPT_MAXREDIRS, (xm&xmode_noredirs)?0:5); | 227 | CURLcode r = easy_setopt(CURLOPT_MAXREDIRS, (xm&xmode_noredirs)?0:5); |
228 | if(r) | 228 | if(r) |
229 | throw exception_curl(OPKELE_CP_ "failed to set curly maxredirs option"); | 229 | throw exception_curl(OPKELE_CP_ "failed to set curly maxredirs option"); |
230 | if( (r=easy_setopt(CURLOPT_URL,url.c_str())) ) | 230 | if( (r=easy_setopt(CURLOPT_URL,url.c_str())) ) |
231 | throw exception_curl(OPKELE_CP_ "failed to set curly urlie",r); | 231 | throw exception_curl(OPKELE_CP_ "failed to set curly urlie",r); |
232 | 232 | ||
233 | http_content_type.clear(); | 233 | http_content_type.clear(); |
234 | xmode = xm; | 234 | xmode = xm; |
235 | prepare_to_parse(); | 235 | prepare_to_parse(); |
236 | if(xmode&xmode_html) { | 236 | if(xmode&xmode_html) { |
237 | xrds_location.clear(); | 237 | xrds_location.clear(); |
238 | save_html.clear(); | 238 | save_html.clear(); |
239 | save_html.reserve(max_html); | 239 | save_html.reserve(max_html); |
240 | } | 240 | } |
241 | xrd = &idis.xrd; | 241 | xrd = &idis.xrd; |
242 | 242 | ||
243 | r = easy_perform(); | 243 | r = easy_perform(); |
244 | if(r && r!=CURLE_WRITE_ERROR) | 244 | if(r && r!=CURLE_WRITE_ERROR) |
245 | throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); | 245 | throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); |
246 | 246 | ||
247 | if(!parser_choked) { | 247 | if(!parser_choked) { |
248 | parse(0,0,true); | 248 | parse(0,0,true); |
249 | }else if(xmode&xmode_html){ | 249 | }else if(xmode&xmode_html){ |
250 | /* TODO: do not bother if we've seen xml */ | 250 | /* TODO: do not bother if we've seen xml */ |
251 | try { | 251 | try { |
252 | util::tidy_doc_t td = util::tidy_doc_t::create(); | 252 | util::tidy_doc_t td = util::tidy_doc_t::create(); |
253 | if(!td) | 253 | if(!td) |
254 | throw exception_tidy(OPKELE_CP_ "failed to create htmltidy document"); | 254 | throw exception_tidy(OPKELE_CP_ "failed to create htmltidy document"); |
255 | #ifndef NDEBUG | 255 | #ifndef NDEBUG |
256 | td.opt_set(TidyQuiet,false); | 256 | td.opt_set(TidyQuiet,false); |
257 | td.opt_set(TidyShowWarnings,false); | 257 | td.opt_set(TidyShowWarnings,false); |
258 | #endif /* NDEBUG */ | 258 | #endif /* NDEBUG */ |
259 | td.opt_set(TidyForceOutput,true); | 259 | td.opt_set(TidyForceOutput,true); |
260 | td.opt_set(TidyXhtmlOut,true); | 260 | td.opt_set(TidyXhtmlOut,true); |
261 | td.opt_set(TidyDoctypeMode,TidyDoctypeOmit); | 261 | td.opt_set(TidyDoctypeMode,TidyDoctypeOmit); |
262 | td.opt_set(TidyMark,false); | 262 | td.opt_set(TidyMark,false); |
263 | td.opt_set(TidyNumEntities,true); | ||
263 | if(td.parse_string(save_html)<=0) | 264 | if(td.parse_string(save_html)<=0) |
264 | throw exception_tidy(OPKELE_CP_ "tidy failed to parse document"); | 265 | throw exception_tidy(OPKELE_CP_ "tidy failed to parse document"); |
265 | if(td.clean_and_repair()<=0) | 266 | if(td.clean_and_repair()<=0) |
266 | throw exception_tidy(OPKELE_CP_ "tidy failed to clean and repair"); | 267 | throw exception_tidy(OPKELE_CP_ "tidy failed to clean and repair"); |
267 | util::tidy_buf_t tide; | 268 | util::tidy_buf_t tide; |
268 | if(td.save_buffer(tide)<=0) | 269 | if(td.save_buffer(tide)<=0) |
269 | throw exception_tidy(OPKELE_CP_ "tidy failed to save buffer"); | 270 | throw exception_tidy(OPKELE_CP_ "tidy failed to save buffer"); |
270 | prepare_to_parse(); | 271 | prepare_to_parse(); |
271 | parse(tide.c_str(),tide.size(),true); | 272 | parse(tide.c_str(),tide.size(),true); |
272 | }catch(exception_tidy& et) { } | 273 | }catch(exception_tidy& et) { } |
273 | } | 274 | } |
274 | save_html.clear(); | 275 | save_html.clear(); |
275 | } | 276 | } |
276 | 277 | ||
277 | void prepare_to_parse() { | 278 | void prepare_to_parse() { |
278 | (*(expat_t*)this) = parser_create_ns(); | 279 | (*(expat_t*)this) = parser_create_ns(); |
279 | set_user_data(); set_element_handler(); | 280 | set_user_data(); set_element_handler(); |
280 | set_character_data_handler(); | 281 | set_character_data_handler(); |
281 | 282 | ||
282 | if(xmode&xmode_html) { | 283 | if(xmode&xmode_html) { |
283 | html_openid1.clear(); html_openid2.clear(); | 284 | html_openid1.clear(); html_openid2.clear(); |
284 | parser_choked = false; | 285 | parser_choked = false; |
285 | } | 286 | } |
286 | 287 | ||
287 | cdata = 0; xrd_service = 0; skipping = 0; | 288 | cdata = 0; xrd_service = 0; skipping = 0; |
288 | pt_stack.clear(); | 289 | pt_stack.clear(); |
289 | status_code = 100; status_string.clear(); | 290 | status_code = 100; status_string.clear(); |
290 | } | 291 | } |
291 | 292 | ||
292 | void html2xrd(endpoint_discovery_iterator& oi,idiscovery_t& id) { | 293 | void html2xrd(endpoint_discovery_iterator& oi,idiscovery_t& id) { |
293 | XRD_t& x = id.xrd; | 294 | XRD_t& x = id.xrd; |
294 | if(!html_openid2.uris.empty()) { | 295 | if(!html_openid2.uris.empty()) { |
295 | html_openid2.types.insert(STURI_OPENID20); | 296 | html_openid2.types.insert(STURI_OPENID20); |
296 | x.services.add(-1,html_openid2); | 297 | x.services.add(-1,html_openid2); |
297 | queue_endpoints(oi,id,&op_service_types[st_index_2]); | 298 | queue_endpoints(oi,id,&op_service_types[st_index_2]); |
298 | } | 299 | } |
299 | if(!html_openid1.uris.empty()) { | 300 | if(!html_openid1.uris.empty()) { |
300 | html_openid1.types.insert(STURI_OPENID11); | 301 | html_openid1.types.insert(STURI_OPENID11); |
301 | x.services.add(-1,html_openid1); | 302 | x.services.add(-1,html_openid1); |
302 | queue_endpoints(oi,id,&op_service_types[st_index_1]); | 303 | queue_endpoints(oi,id,&op_service_types[st_index_1]); |
303 | } | 304 | } |
304 | } | 305 | } |
305 | 306 | ||
306 | size_t write(void *p,size_t s,size_t nm) { | 307 | size_t write(void *p,size_t s,size_t nm) { |
307 | /* TODO: limit total size */ | 308 | /* TODO: limit total size */ |
308 | size_t bytes = s*nm; | 309 | size_t bytes = s*nm; |
309 | const char *inbuf = (const char*)p; | 310 | const char *inbuf = (const char*)p; |
310 | if(xmode&xmode_html) { | 311 | if(xmode&xmode_html) { |
311 | size_t mbts = save_html.capacity()-save_html.size(); | 312 | size_t mbts = save_html.capacity()-save_html.size(); |
312 | size_t bts = 0; | 313 | size_t bts = 0; |
313 | if(mbts>0) { | 314 | if(mbts>0) { |
314 | bts = (bytes>mbts)?mbts:bytes; | 315 | bts = (bytes>mbts)?mbts:bytes; |
315 | save_html.append(inbuf,bts); | 316 | save_html.append(inbuf,bts); |
316 | } | 317 | } |
317 | if(skipping<0) return bts; | 318 | if(skipping<0) return bts; |
318 | } | 319 | } |
319 | if(skipping<0) return 0; | 320 | if(skipping<0) return 0; |
320 | bool rp = parse(inbuf,bytes,false); | 321 | bool rp = parse(inbuf,bytes,false); |
321 | if(!rp) { | 322 | if(!rp) { |
322 | parser_choked = true; | 323 | parser_choked = true; |
323 | skipping = -1; | 324 | skipping = -1; |
324 | if(!(xmode&xmode_html)) | 325 | if(!(xmode&xmode_html)) |
325 | bytes = 0; | 326 | bytes = 0; |
326 | } | 327 | } |
327 | return bytes; | 328 | return bytes; |
328 | } | 329 | } |
329 | size_t header(void *p,size_t s,size_t nm) { | 330 | size_t header(void *p,size_t s,size_t nm) { |
330 | size_t bytes = s*nm; | 331 | size_t bytes = s*nm; |
331 | const char *h = (const char*)p; | 332 | const char *h = (const char*)p; |
332 | const char *colon = (const char*)memchr(p,':',bytes); | 333 | const char *colon = (const char*)memchr(p,':',bytes); |
333 | const char *space = (const char*)memchr(p,' ',bytes); | 334 | const char *space = (const char*)memchr(p,' ',bytes); |
334 | if(space && ( (!colon) || space<colon ) ) { | 335 | if(space && ( (!colon) || space<colon ) ) { |
335 | xrds_location.clear(); http_content_type.clear(); | 336 | xrds_location.clear(); http_content_type.clear(); |
336 | }else if(colon) { | 337 | }else if(colon) { |
337 | const char *hv = ++colon; | 338 | const char *hv = ++colon; |
338 | size_t hnl = colon-h; | 339 | size_t hnl = colon-h; |
339 | int rb; | 340 | int rb; |
340 | for(rb = bytes-hnl-1;rb>0 && isspace(*hv);++hv,--rb); | 341 | for(rb = bytes-hnl-1;rb>0 && isspace(*hv);++hv,--rb); |
341 | while(rb>0 && isspace(hv[rb-1])) --rb; | 342 | while(rb>0 && isspace(hv[rb-1])) --rb; |
342 | if(rb) { | 343 | if(rb) { |
343 | if( (hnl>=sizeof(XRDS_HEADER)) | 344 | if( (hnl>=sizeof(XRDS_HEADER)) |
344 | && !strncasecmp(h,XRDS_HEADER":", | 345 | && !strncasecmp(h,XRDS_HEADER":", |
345 | sizeof(XRDS_HEADER)) ) { | 346 | sizeof(XRDS_HEADER)) ) { |
346 | xrds_location.assign(hv,rb); | 347 | xrds_location.assign(hv,rb); |
347 | }else if( (hnl>=sizeof(CT_HEADER)) | 348 | }else if( (hnl>=sizeof(CT_HEADER)) |
348 | && !strncasecmp(h,CT_HEADER":", | 349 | && !strncasecmp(h,CT_HEADER":", |
349 | sizeof(CT_HEADER)) ) { | 350 | sizeof(CT_HEADER)) ) { |
350 | const char *sc = (const char*)memchr( | 351 | const char *sc = (const char*)memchr( |
351 | hv,';',rb); | 352 | hv,';',rb); |
352 | http_content_type.assign(hv,sc?(sc-hv):rb); | 353 | http_content_type.assign(hv,sc?(sc-hv):rb); |
353 | } | 354 | } |
354 | } | 355 | } |
355 | } | 356 | } |
356 | return curl_t::header(p,s,nm); | 357 | return curl_t::header(p,s,nm); |
357 | } | 358 | } |
358 | 359 | ||
359 | void start_element(const XML_Char *n,const XML_Char **a) { | 360 | void start_element(const XML_Char *n,const XML_Char **a) { |
360 | if(skipping<0) return; | 361 | if(skipping<0) return; |
361 | if(skipping) { | 362 | if(skipping) { |
362 | if(xmode&xmode_html) | 363 | if(xmode&xmode_html) |
363 | html_start_element(n,a); | 364 | html_start_element(n,a); |
364 | ++skipping; return; | 365 | ++skipping; return; |
365 | } | 366 | } |
366 | if(pt_stack.empty()) { | 367 | if(pt_stack.empty()) { |
367 | if(is_qelement(n,NSURI_XRDS "\tXRDS")) | 368 | if(is_qelement(n,NSURI_XRDS "\tXRDS")) |
368 | return; | 369 | return; |
369 | if(is_qelement(n,NSURI_XRD "\tXRD")) { | 370 | if(is_qelement(n,NSURI_XRD "\tXRD")) { |
370 | assert(xrd); | 371 | assert(xrd); |
371 | xrd->clear(); | 372 | xrd->clear(); |
372 | pt_stack.push_back(n); | 373 | pt_stack.push_back(n); |
373 | }else if(xmode&xmode_html) { | 374 | }else if(xmode&xmode_html) { |
374 | html_start_element(n,a); | 375 | html_start_element(n,a); |
375 | }else{ | 376 | }else{ |
376 | skipping = -1; | 377 | skipping = -1; |
377 | } | 378 | } |
378 | }else{ | 379 | }else{ |
379 | int pt_s = pt_stack.size(); | 380 | int pt_s = pt_stack.size(); |
380 | if(pt_s==1) { | 381 | if(pt_s==1) { |
381 | if(is_qelement(n,NSURI_XRD "\tCanonicalID")) { | 382 | if(is_qelement(n,NSURI_XRD "\tCanonicalID")) { |
382 | assert(xrd); | 383 | assert(xrd); |
383 | cdata = &(xrd->canonical_ids.add(element_priority(a),string())); | 384 | cdata = &(xrd->canonical_ids.add(element_priority(a),string())); |
384 | }else if(is_qelement(n,NSURI_XRD "\tLocalID")) { | 385 | }else if(is_qelement(n,NSURI_XRD "\tLocalID")) { |
385 | assert(xrd); | 386 | assert(xrd); |
386 | cdata = &(xrd->local_ids.add(element_priority(a),string())); | 387 | cdata = &(xrd->local_ids.add(element_priority(a),string())); |
387 | }else if(is_qelement(n,NSURI_XRD "\tProviderID")) { | 388 | }else if(is_qelement(n,NSURI_XRD "\tProviderID")) { |
388 | assert(xrd); | 389 | assert(xrd); |
389 | cdata = &(xrd->provider_id); | 390 | cdata = &(xrd->provider_id); |
390 | }else if(is_qelement(n,NSURI_XRD "\tService")) { | 391 | }else if(is_qelement(n,NSURI_XRD "\tService")) { |
391 | assert(xrd); | 392 | assert(xrd); |
392 | xrd_service = &(xrd->services.add(element_priority(a), | 393 | xrd_service = &(xrd->services.add(element_priority(a), |
393 | service_t())); | 394 | service_t())); |
394 | pt_stack.push_back(n); | 395 | pt_stack.push_back(n); |
395 | }else if(is_qelement(n,NSURI_XRD "\tStatus")) { | 396 | }else if(is_qelement(n,NSURI_XRD "\tStatus")) { |
396 | for(;*a;) { | 397 | for(;*a;) { |
397 | if(!strcasecmp(*(a++),"code")) { | 398 | if(!strcasecmp(*(a++),"code")) { |
398 | if(sscanf(*(a++),"%ld",&status_code)==1 && status_code!=100) { | 399 | if(sscanf(*(a++),"%ld",&status_code)==1 && status_code!=100) { |
399 | cdata = &status_string; | 400 | cdata = &status_string; |
400 | pt_stack.push_back(n); | 401 | pt_stack.push_back(n); |
401 | break; | 402 | break; |
402 | } | 403 | } |
403 | }else | 404 | }else |
404 | ++a; | 405 | ++a; |
405 | } | 406 | } |
406 | }else if(is_qelement(n,NSURI_XRD "\tExpires")) { | 407 | }else if(is_qelement(n,NSURI_XRD "\tExpires")) { |
407 | assert(xrd); | 408 | assert(xrd); |
408 | cdata_buf.clear(); | 409 | cdata_buf.clear(); |
409 | cdata = &cdata_buf; | 410 | cdata = &cdata_buf; |
410 | }else if(xmode&xmode_html) { | 411 | }else if(xmode&xmode_html) { |
411 | html_start_element(n,a); | 412 | html_start_element(n,a); |
412 | }else{ | 413 | }else{ |
413 | skipping = 1; | 414 | skipping = 1; |
414 | } | 415 | } |
415 | }else if(pt_s==2) { | 416 | }else if(pt_s==2) { |
416 | if(is_qelement(pt_stack.back().c_str(), NSURI_XRD "\tService")) { | 417 | if(is_qelement(pt_stack.back().c_str(), NSURI_XRD "\tService")) { |
417 | if(is_qelement(n,NSURI_XRD "\tType")) { | 418 | if(is_qelement(n,NSURI_XRD "\tType")) { |
418 | assert(xrd); assert(xrd_service); | 419 | assert(xrd); assert(xrd_service); |
419 | cdata_buf.clear(); | 420 | cdata_buf.clear(); |
420 | cdata = &cdata_buf; | 421 | cdata = &cdata_buf; |
421 | }else if(is_qelement(n,NSURI_XRD "\tURI")) { | 422 | }else if(is_qelement(n,NSURI_XRD "\tURI")) { |
422 | assert(xrd); assert(xrd_service); | 423 | assert(xrd); assert(xrd_service); |
423 | const char *append = element_attr(a,"append"); | 424 | const char *append = element_attr(a,"append"); |
424 | xrd::uri_t& uri = xrd_service->uris.add(element_priority(a),xrd::uri_t("",append?append:"")); | 425 | xrd::uri_t& uri = xrd_service->uris.add(element_priority(a),xrd::uri_t("",append?append:"")); |
425 | cdata = &uri.uri; | 426 | cdata = &uri.uri; |
426 | }else if(is_qelement(n,NSURI_XRD "\tLocalID") | 427 | }else if(is_qelement(n,NSURI_XRD "\tLocalID") |
427 | || is_qelement(n,NSURI_OPENID10 "\tDelegate") ) { | 428 | || is_qelement(n,NSURI_OPENID10 "\tDelegate") ) { |
428 | assert(xrd); assert(xrd_service); | 429 | assert(xrd); assert(xrd_service); |
429 | cdata = &(xrd_service->local_ids.add(element_priority(a),string())); | 430 | cdata = &(xrd_service->local_ids.add(element_priority(a),string())); |
430 | }else if(is_qelement(n,NSURI_XRD "\tProviderID")) { | 431 | }else if(is_qelement(n,NSURI_XRD "\tProviderID")) { |
431 | assert(xrd); assert(xrd_service); | 432 | assert(xrd); assert(xrd_service); |
432 | cdata = &(xrd_service->provider_id); | 433 | cdata = &(xrd_service->provider_id); |
433 | }else{ | 434 | }else{ |
434 | skipping = 1; | 435 | skipping = 1; |
435 | } | 436 | } |
436 | }else | 437 | }else |
437 | skipping = 1; | 438 | skipping = 1; |
438 | }else if(xmode&xmode_html) { | 439 | }else if(xmode&xmode_html) { |
439 | html_start_element(n,a); | 440 | html_start_element(n,a); |
440 | }else{ | 441 | }else{ |
441 | skipping = 1; | 442 | skipping = 1; |
442 | } | 443 | } |
443 | } | 444 | } |
444 | } | 445 | } |
445 | void end_element(const XML_Char *n) { | 446 | void end_element(const XML_Char *n) { |
446 | if(skipping<0) return; | 447 | if(skipping<0) return; |
447 | if(skipping) { | 448 | if(skipping) { |
448 | --skipping; return; | 449 | --skipping; return; |
449 | } | 450 | } |
450 | if(is_qelement(n,NSURI_XRD "\tType")) { | 451 | if(is_qelement(n,NSURI_XRD "\tType")) { |
451 | assert(xrd); assert(xrd_service); assert(cdata==&cdata_buf); | 452 | assert(xrd); assert(xrd_service); assert(cdata==&cdata_buf); |
452 | xrd_service->types.insert(cdata_buf); | 453 | xrd_service->types.insert(cdata_buf); |
453 | }else if(is_qelement(n,NSURI_XRD "\tService")) { | 454 | }else if(is_qelement(n,NSURI_XRD "\tService")) { |
454 | assert(xrd); assert(xrd_service); | 455 | assert(xrd); assert(xrd_service); |
455 | assert(!pt_stack.empty()); | 456 | assert(!pt_stack.empty()); |
456 | assert(pt_stack.back()==(NSURI_XRD "\tService")); | 457 | assert(pt_stack.back()==(NSURI_XRD "\tService")); |
457 | pt_stack.pop_back(); | 458 | pt_stack.pop_back(); |
458 | xrd_service = 0; | 459 | xrd_service = 0; |
459 | }else if(is_qelement(n,NSURI_XRD "\tStatus")) { | 460 | }else if(is_qelement(n,NSURI_XRD "\tStatus")) { |
460 | assert(xrd); | 461 | assert(xrd); |
461 | if(is_qelement(pt_stack.back().c_str(),n)) { | 462 | if(is_qelement(pt_stack.back().c_str(),n)) { |
462 | assert(cdata==&status_string); | 463 | assert(cdata==&status_string); |
463 | pt_stack.pop_back(); | 464 | pt_stack.pop_back(); |
464 | if(status_code!=100) | 465 | if(status_code!=100) |
465 | skipping = -1; | 466 | skipping = -1; |
466 | } | 467 | } |
467 | }else if(is_qelement(n,NSURI_XRD "\tExpires")) { | 468 | }else if(is_qelement(n,NSURI_XRD "\tExpires")) { |
468 | assert(xrd); | 469 | assert(xrd); |
469 | xrd->expires = util::w3c_to_time(cdata_buf); | 470 | xrd->expires = util::w3c_to_time(cdata_buf); |
470 | }else if((xmode&xmode_html) && is_element(n,"head")) { | 471 | }else if((xmode&xmode_html) && is_element(n,"head")) { |
471 | skipping = -1; | 472 | skipping = -1; |
472 | } | 473 | } |
473 | cdata = 0; | 474 | cdata = 0; |
474 | } | 475 | } |
475 | void character_data(const XML_Char *s,int l) { | 476 | void character_data(const XML_Char *s,int l) { |
476 | if(skipping) return; | 477 | if(skipping) return; |
477 | if(cdata) cdata->append(s,l); | 478 | if(cdata) cdata->append(s,l); |
478 | } | 479 | } |
479 | 480 | ||
480 | void html_start_element(const XML_Char *n,const XML_Char **a) { | 481 | void html_start_element(const XML_Char *n,const XML_Char **a) { |
481 | if(is_element(n,"meta")) { | 482 | if(is_element(n,"meta")) { |
482 | bool heq = false; | 483 | bool heq = false; |
483 | string l; | 484 | string l; |
484 | for(;*a;a+=2) { | 485 | for(;*a;a+=2) { |
485 | if(!( strcasecmp(a[0],"http-equiv") | 486 | if(!( strcasecmp(a[0],"http-equiv") |
486 | || strcasecmp(a[1],XRDS_HEADER) )) | 487 | || strcasecmp(a[1],XRDS_HEADER) )) |
487 | heq = true; | 488 | heq = true; |
488 | else if(!strcasecmp(a[0],"content")) | 489 | else if(!strcasecmp(a[0],"content")) |
489 | l.assign(a[1]); | 490 | l.assign(a[1]); |
490 | } | 491 | } |
491 | if(heq) | 492 | if(heq) |
492 | xrds_location = l; | 493 | xrds_location = l; |
493 | }else if(is_element(n,"link")) { | 494 | }else if(is_element(n,"link")) { |
494 | string rels; | 495 | string rels; |
495 | string href; | 496 | string href; |
496 | for(;*a;a+=2) { | 497 | for(;*a;a+=2) { |
497 | if( !strcasecmp(a[0],"rel") ) { | 498 | if( !strcasecmp(a[0],"rel") ) { |
498 | rels.assign(a[1]); | 499 | rels.assign(a[1]); |
499 | }else if( !strcasecmp(a[0],"href") ) { | 500 | }else if( !strcasecmp(a[0],"href") ) { |
500 | const char *ns = a[1]; | 501 | const char *ns = a[1]; |
501 | for(;*ns && isspace(*ns);++ns); | 502 | for(;*ns && isspace(*ns);++ns); |
502 | href.assign(ns); | 503 | href.assign(ns); |
503 | string::size_type lns=href.find_last_not_of(data::_whitespace_chars); | 504 | string::size_type lns=href.find_last_not_of(data::_whitespace_chars); |
504 | href.erase(lns+1); | 505 | href.erase(lns+1); |
505 | } | 506 | } |
506 | } | 507 | } |
507 | for(string::size_type ns=rels.find_first_not_of(data::_whitespace_chars); | 508 | for(string::size_type ns=rels.find_first_not_of(data::_whitespace_chars); |
508 | ns!=string::npos; ns=rels.find_first_not_of(data::_whitespace_chars,ns)) { | 509 | ns!=string::npos; ns=rels.find_first_not_of(data::_whitespace_chars,ns)) { |
509 | string::size_type s = rels.find_first_of(data::_whitespace_chars,ns); | 510 | string::size_type s = rels.find_first_of(data::_whitespace_chars,ns); |
510 | string rel; | 511 | string rel; |
511 | if(s==string::npos) { | 512 | if(s==string::npos) { |
512 | rel.assign(rels,ns,string::npos); | 513 | rel.assign(rels,ns,string::npos); |
513 | ns = string::npos; | 514 | ns = string::npos; |
514 | }else{ | 515 | }else{ |
515 | rel.assign(rels,ns,s-ns); | 516 | rel.assign(rels,ns,s-ns); |
516 | ns = s; | 517 | ns = s; |
517 | } | 518 | } |
518 | if(rel=="openid.server") | 519 | if(rel=="openid.server") |
519 | html_openid1.uris.add(-1,xrd::uri_t(href)); | 520 | html_openid1.uris.add(-1,xrd::uri_t(href)); |
520 | else if(rel=="openid.delegate") | 521 | else if(rel=="openid.delegate") |
521 | html_openid1.local_ids.add(-1,href); | 522 | html_openid1.local_ids.add(-1,href); |
522 | else if(rel=="openid2.provider") | 523 | else if(rel=="openid2.provider") |
523 | html_openid2.uris.add(-1,xrd::uri_t(href)); | 524 | html_openid2.uris.add(-1,xrd::uri_t(href)); |
524 | else if(rel=="openid2.local_id") | 525 | else if(rel=="openid2.local_id") |
525 | html_openid2.local_ids.add(-1,href); | 526 | html_openid2.local_ids.add(-1,href); |
526 | } | 527 | } |
527 | }else if(is_element(n,"body")) { | 528 | }else if(is_element(n,"body")) { |
528 | skipping = -1; | 529 | skipping = -1; |
529 | } | 530 | } |
530 | } | 531 | } |
531 | 532 | ||
532 | void queue_endpoints(endpoint_discovery_iterator& oi, | 533 | void queue_endpoints(endpoint_discovery_iterator& oi, |
533 | const idiscovery_t &id, | 534 | const idiscovery_t &id, |
534 | const service_type_t *st) { | 535 | const service_type_t *st) { |
535 | openid_endpoint_t ep; | 536 | openid_endpoint_t ep; |
536 | ep.claimed_id = id.canonicalized_id; | 537 | ep.claimed_id = id.canonicalized_id; |
537 | for(xrd::services_t::const_iterator isvc=id.xrd.services.begin(); | 538 | for(xrd::services_t::const_iterator isvc=id.xrd.services.begin(); |
538 | isvc!=id.xrd.services.end(); ++isvc) { | 539 | isvc!=id.xrd.services.end(); ++isvc) { |
539 | const xrd::service_t svc = isvc->second; | 540 | const xrd::service_t svc = isvc->second; |
540 | if(svc.types.find(st->uri)==svc.types.end()) continue; | 541 | if(svc.types.find(st->uri)==svc.types.end()) continue; |
541 | for(xrd::uris_t::const_iterator iu=svc.uris.begin();iu!=svc.uris.end();++iu) { | 542 | for(xrd::uris_t::const_iterator iu=svc.uris.begin();iu!=svc.uris.end();++iu) { |
542 | ep.uri = iu->second.uri; | 543 | ep.uri = iu->second.uri; |
543 | if(id.xri_identity) { | 544 | if(id.xri_identity) { |
544 | if(iu->second.append=="qxri") { | 545 | if(iu->second.append=="qxri") { |
545 | ep.uri += id.normalized_id; | 546 | ep.uri += id.normalized_id; |
546 | } /* TODO: else handle other append attribute values */ | 547 | } /* TODO: else handle other append attribute values */ |
547 | } | 548 | } |
548 | if(st->forceid) { | 549 | if(st->forceid) { |
549 | ep.local_id = ep.claimed_id = st->forceid; | 550 | ep.local_id = ep.claimed_id = st->forceid; |
550 | *(oi++) = ep; | 551 | *(oi++) = ep; |
551 | }else{ | 552 | }else{ |
552 | if(svc.local_ids.empty()) { | 553 | if(svc.local_ids.empty()) { |
553 | ep.local_id = ep.claimed_id; | 554 | ep.local_id = ep.claimed_id; |
554 | *(oi++) = ep; | 555 | *(oi++) = ep; |
555 | }else{ | 556 | }else{ |
556 | for(xrd::local_ids_t::const_iterator ilid=svc.local_ids.begin(); | 557 | for(xrd::local_ids_t::const_iterator ilid=svc.local_ids.begin(); |
557 | ilid!=svc.local_ids.end(); ++ilid) { | 558 | ilid!=svc.local_ids.end(); ++ilid) { |
558 | ep.local_id = ilid->second; | 559 | ep.local_id = ilid->second; |
559 | *(oi++) = ep; | 560 | *(oi++) = ep; |
560 | } | 561 | } |
561 | } | 562 | } |
562 | } | 563 | } |
563 | } | 564 | } |
564 | } | 565 | } |
565 | } | 566 | } |
566 | 567 | ||
567 | }; | 568 | }; |
568 | 569 | ||
569 | string idiscover(endpoint_discovery_iterator oi,const string& identity) { | 570 | string idiscover(endpoint_discovery_iterator oi,const string& identity) { |
570 | idigger_t idigger; | 571 | idigger_t idigger; |
571 | return idigger.discover(oi,identity); | 572 | return idigger.discover(oi,identity); |
572 | } | 573 | } |
573 | 574 | ||
574 | void yadiscover(endpoint_discovery_iterator oi,const string& yurl,const char **types,bool redirs) try { | 575 | void yadiscover(endpoint_discovery_iterator oi,const string& yurl,const char **types,bool redirs) try { |
575 | idigger_t idigger; | 576 | idigger_t idigger; |
576 | idigger.yadiscover(oi,yurl,types,redirs); | 577 | idigger.yadiscover(oi,yurl,types,redirs); |
577 | }catch(exception_curl& ec) { | 578 | }catch(exception_curl& ec) { |
578 | if(redirs || ec._error!=CURLE_TOO_MANY_REDIRECTS) | 579 | if(redirs || ec._error!=CURLE_TOO_MANY_REDIRECTS) |
579 | throw; | 580 | throw; |
580 | } | 581 | } |
581 | 582 | ||
582 | } | 583 | } |