-rw-r--r-- | lib/discovery.cc | 6 |
1 files changed, 6 insertions, 0 deletions
diff --git a/lib/discovery.cc b/lib/discovery.cc index bc7d6fb..81727c0 100644 --- a/lib/discovery.cc +++ b/lib/discovery.cc | |||
@@ -143,229 +143,235 @@ namespace opkele { | |||
143 | set_user_data(); set_element_handler(); | 143 | set_user_data(); set_element_handler(); |
144 | set_character_data_handler(); | 144 | set_character_data_handler(); |
145 | 145 | ||
146 | http_content_type.clear(); | 146 | http_content_type.clear(); |
147 | xmode = xm; | 147 | xmode = xm; |
148 | if(xmode&xmode_html) { | 148 | if(xmode&xmode_html) { |
149 | xrds_location.clear(); | 149 | xrds_location.clear(); |
150 | html_openid1.clear(); html_openid2.clear(); | 150 | html_openid1.clear(); html_openid2.clear(); |
151 | } | 151 | } |
152 | xrd = &result.xrd; | 152 | xrd = &result.xrd; |
153 | cdata = 0; xrd_service = 0; skipping = 0; | 153 | cdata = 0; xrd_service = 0; skipping = 0; |
154 | status_code = 100; status_string.clear(); | 154 | status_code = 100; status_string.clear(); |
155 | 155 | ||
156 | r = easy_perform(); | 156 | r = easy_perform(); |
157 | if(r && r!=CURLE_WRITE_ERROR) | 157 | if(r && r!=CURLE_WRITE_ERROR) |
158 | throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); | 158 | throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); |
159 | 159 | ||
160 | parse(0,0,true); | 160 | parse(0,0,true); |
161 | } | 161 | } |
162 | 162 | ||
163 | void html2xrd(XRD_t& x) { | 163 | void html2xrd(XRD_t& x) { |
164 | if(!html_openid1.uris.empty()) { | 164 | if(!html_openid1.uris.empty()) { |
165 | html_openid1.types.insert(STURI_OPENID11); | 165 | html_openid1.types.insert(STURI_OPENID11); |
166 | x.services.add(-1,html_openid1); | 166 | x.services.add(-1,html_openid1); |
167 | } | 167 | } |
168 | if(!html_openid2.uris.empty()) { | 168 | if(!html_openid2.uris.empty()) { |
169 | html_openid2.types.insert(STURI_OPENID20); | 169 | html_openid2.types.insert(STURI_OPENID20); |
170 | x.services.add(-1,html_openid2); | 170 | x.services.add(-1,html_openid2); |
171 | } | 171 | } |
172 | } | 172 | } |
173 | 173 | ||
174 | size_t write(void *p,size_t s,size_t nm) { | 174 | size_t write(void *p,size_t s,size_t nm) { |
175 | if(skipping<0) return 0; | 175 | if(skipping<0) return 0; |
176 | /* TODO: limit total size */ | 176 | /* TODO: limit total size */ |
177 | size_t bytes = s*nm; | 177 | size_t bytes = s*nm; |
178 | parse((const char *)p,bytes,false); | 178 | parse((const char *)p,bytes,false); |
179 | return bytes; | 179 | return bytes; |
180 | } | 180 | } |
181 | size_t header(void *p,size_t s,size_t nm) { | 181 | size_t header(void *p,size_t s,size_t nm) { |
182 | size_t bytes = s*nm; | 182 | size_t bytes = s*nm; |
183 | const char *h = (const char*)p; | 183 | const char *h = (const char*)p; |
184 | const char *colon = (const char*)memchr(p,':',bytes); | 184 | const char *colon = (const char*)memchr(p,':',bytes); |
185 | const char *space = (const char*)memchr(p,' ',bytes); | 185 | const char *space = (const char*)memchr(p,' ',bytes); |
186 | if(space && ( (!colon) || space<colon ) ) { | 186 | if(space && ( (!colon) || space<colon ) ) { |
187 | xrds_location.clear(); http_content_type.clear(); | 187 | xrds_location.clear(); http_content_type.clear(); |
188 | }else if(colon) { | 188 | }else if(colon) { |
189 | const char *hv = ++colon; | 189 | const char *hv = ++colon; |
190 | int hnl = colon-h; | 190 | int hnl = colon-h; |
191 | int rb; | 191 | int rb; |
192 | for(rb = bytes-hnl-1;rb>0 && isspace(*hv);++hv,--rb); | 192 | for(rb = bytes-hnl-1;rb>0 && isspace(*hv);++hv,--rb); |
193 | while(rb>0 && isspace(hv[rb-1])) --rb; | 193 | while(rb>0 && isspace(hv[rb-1])) --rb; |
194 | if(rb) { | 194 | if(rb) { |
195 | if( (hnl>=sizeof(XRDS_HEADER)) | 195 | if( (hnl>=sizeof(XRDS_HEADER)) |
196 | && !strncasecmp(h,XRDS_HEADER":", | 196 | && !strncasecmp(h,XRDS_HEADER":", |
197 | sizeof(XRDS_HEADER)) ) { | 197 | sizeof(XRDS_HEADER)) ) { |
198 | xrds_location.assign(hv,rb); | 198 | xrds_location.assign(hv,rb); |
199 | }else if( (hnl>=sizeof(CT_HEADER)) | 199 | }else if( (hnl>=sizeof(CT_HEADER)) |
200 | && !strncasecmp(h,CT_HEADER":", | 200 | && !strncasecmp(h,CT_HEADER":", |
201 | sizeof(CT_HEADER)) ) { | 201 | sizeof(CT_HEADER)) ) { |
202 | const char *sc = (const char*)memchr( | 202 | const char *sc = (const char*)memchr( |
203 | hv,';',rb); | 203 | hv,';',rb); |
204 | http_content_type.assign(hv,sc?(sc-hv):rb); | 204 | http_content_type.assign(hv,sc?(sc-hv):rb); |
205 | } | 205 | } |
206 | } | 206 | } |
207 | } | 207 | } |
208 | return curl_t::header(p,s,nm); | 208 | return curl_t::header(p,s,nm); |
209 | } | 209 | } |
210 | 210 | ||
211 | void start_element(const XML_Char *n,const XML_Char **a) { | 211 | void start_element(const XML_Char *n,const XML_Char **a) { |
212 | if(skipping<0) return; | 212 | if(skipping<0) return; |
213 | if(skipping) { | 213 | if(skipping) { |
214 | if(xmode&xmode_html) | 214 | if(xmode&xmode_html) |
215 | html_start_element(n,a); | 215 | html_start_element(n,a); |
216 | ++skipping; return; | 216 | ++skipping; return; |
217 | } | 217 | } |
218 | if(pt_stack.empty()) { | 218 | if(pt_stack.empty()) { |
219 | if(is_qelement(n,NSURI_XRDS "\tXRDS")) | 219 | if(is_qelement(n,NSURI_XRDS "\tXRDS")) |
220 | return; | 220 | return; |
221 | if(is_qelement(n,NSURI_XRD "\tXRD")) { | 221 | if(is_qelement(n,NSURI_XRD "\tXRD")) { |
222 | assert(xrd); | 222 | assert(xrd); |
223 | xrd->clear(); | 223 | xrd->clear(); |
224 | pt_stack.push_back(n); | 224 | pt_stack.push_back(n); |
225 | }else if(xmode&xmode_html) { | 225 | }else if(xmode&xmode_html) { |
226 | html_start_element(n,a); | 226 | html_start_element(n,a); |
227 | }else{ | 227 | }else{ |
228 | skipping = -1; | 228 | skipping = -1; |
229 | } | 229 | } |
230 | }else{ | 230 | }else{ |
231 | int pt_s = pt_stack.size(); | 231 | int pt_s = pt_stack.size(); |
232 | if(pt_s==1) { | 232 | if(pt_s==1) { |
233 | if(is_qelement(n,NSURI_XRD "\tCanonicalID")) { | 233 | if(is_qelement(n,NSURI_XRD "\tCanonicalID")) { |
234 | assert(xrd); | 234 | assert(xrd); |
235 | cdata = &(xrd->canonical_ids.add(element_priority(a),string())); | 235 | cdata = &(xrd->canonical_ids.add(element_priority(a),string())); |
236 | }else if(is_qelement(n,NSURI_XRD "\tLocalID")) { | 236 | }else if(is_qelement(n,NSURI_XRD "\tLocalID")) { |
237 | assert(xrd); | 237 | assert(xrd); |
238 | cdata = &(xrd->local_ids.add(element_priority(a),string())); | 238 | cdata = &(xrd->local_ids.add(element_priority(a),string())); |
239 | }else if(is_qelement(n,NSURI_XRD "\tProviderID")) { | ||
240 | assert(xrd); | ||
241 | cdata = &(xrd->provider_id); | ||
239 | }else if(is_qelement(n,NSURI_XRD "\tService")) { | 242 | }else if(is_qelement(n,NSURI_XRD "\tService")) { |
240 | assert(xrd); | 243 | assert(xrd); |
241 | xrd_service = &(xrd->services.add(element_priority(a), | 244 | xrd_service = &(xrd->services.add(element_priority(a), |
242 | service_t())); | 245 | service_t())); |
243 | pt_stack.push_back(n); | 246 | pt_stack.push_back(n); |
244 | }else if(is_qelement(n,NSURI_XRD "\tStatus")) { | 247 | }else if(is_qelement(n,NSURI_XRD "\tStatus")) { |
245 | for(;*a;) { | 248 | for(;*a;) { |
246 | if(!strcasecmp(*(a++),"code")) { | 249 | if(!strcasecmp(*(a++),"code")) { |
247 | if(sscanf(*(a++),"%ld",&status_code)==1 && status_code!=100) { | 250 | if(sscanf(*(a++),"%ld",&status_code)==1 && status_code!=100) { |
248 | cdata = &status_string; | 251 | cdata = &status_string; |
249 | pt_stack.push_back(n); | 252 | pt_stack.push_back(n); |
250 | break; | 253 | break; |
251 | } | 254 | } |
252 | } | 255 | } |
253 | } | 256 | } |
254 | }else if(is_qelement(n,NSURI_XRD "\tExpires")) { | 257 | }else if(is_qelement(n,NSURI_XRD "\tExpires")) { |
255 | assert(xrd); | 258 | assert(xrd); |
256 | cdata_buf.clear(); | 259 | cdata_buf.clear(); |
257 | cdata = &cdata_buf; | 260 | cdata = &cdata_buf; |
258 | }else if(xmode&xmode_html) { | 261 | }else if(xmode&xmode_html) { |
259 | html_start_element(n,a); | 262 | html_start_element(n,a); |
260 | }else{ | 263 | }else{ |
261 | skipping = 1; | 264 | skipping = 1; |
262 | } | 265 | } |
263 | }else if(pt_s==2) { | 266 | }else if(pt_s==2) { |
264 | if(is_qelement(pt_stack.back().c_str(), NSURI_XRD "\tService")) { | 267 | if(is_qelement(pt_stack.back().c_str(), NSURI_XRD "\tService")) { |
265 | if(is_qelement(n,NSURI_XRD "\tType")) { | 268 | if(is_qelement(n,NSURI_XRD "\tType")) { |
266 | assert(xrd); assert(xrd_service); | 269 | assert(xrd); assert(xrd_service); |
267 | cdata_buf.clear(); | 270 | cdata_buf.clear(); |
268 | cdata = &cdata_buf; | 271 | cdata = &cdata_buf; |
269 | }else if(is_qelement(n,NSURI_XRD "\tURI")) { | 272 | }else if(is_qelement(n,NSURI_XRD "\tURI")) { |
270 | assert(xrd); assert(xrd_service); | 273 | assert(xrd); assert(xrd_service); |
271 | cdata = &(xrd_service->uris.add(element_priority(a),string())); | 274 | cdata = &(xrd_service->uris.add(element_priority(a),string())); |
272 | }else if(is_qelement(n,NSURI_XRD "\tLocalID") | 275 | }else if(is_qelement(n,NSURI_XRD "\tLocalID") |
273 | || is_qelement(n,NSURI_OPENID10 "\tDelegate") ) { | 276 | || is_qelement(n,NSURI_OPENID10 "\tDelegate") ) { |
274 | assert(xrd); assert(xrd_service); | 277 | assert(xrd); assert(xrd_service); |
275 | cdata = &(xrd_service->local_ids.add(element_priority(a),string())); | 278 | cdata = &(xrd_service->local_ids.add(element_priority(a),string())); |
279 | }else if(is_qelement(n,NSURI_XRD "\tProviderID")) { | ||
280 | assert(xrd); assert(xrd_service); | ||
281 | cdata = &(xrd_service->provider_id); | ||
276 | }else{ | 282 | }else{ |
277 | skipping = 1; | 283 | skipping = 1; |
278 | } | 284 | } |
279 | }else | 285 | }else |
280 | skipping = 1; | 286 | skipping = 1; |
281 | }else if(xmode&xmode_html) { | 287 | }else if(xmode&xmode_html) { |
282 | html_start_element(n,a); | 288 | html_start_element(n,a); |
283 | }else{ | 289 | }else{ |
284 | skipping = 1; | 290 | skipping = 1; |
285 | } | 291 | } |
286 | } | 292 | } |
287 | } | 293 | } |
288 | void end_element(const XML_Char *n) { | 294 | void end_element(const XML_Char *n) { |
289 | if(skipping<0) return; | 295 | if(skipping<0) return; |
290 | if(skipping) { | 296 | if(skipping) { |
291 | --skipping; return; | 297 | --skipping; return; |
292 | } | 298 | } |
293 | if(is_qelement(n,NSURI_XRD "\tType")) { | 299 | if(is_qelement(n,NSURI_XRD "\tType")) { |
294 | assert(xrd); assert(xrd_service); assert(cdata==&cdata_buf); | 300 | assert(xrd); assert(xrd_service); assert(cdata==&cdata_buf); |
295 | xrd_service->types.insert(cdata_buf); | 301 | xrd_service->types.insert(cdata_buf); |
296 | }else if(is_qelement(n,NSURI_XRD "\tService")) { | 302 | }else if(is_qelement(n,NSURI_XRD "\tService")) { |
297 | assert(xrd); assert(xrd_service); | 303 | assert(xrd); assert(xrd_service); |
298 | assert(!pt_stack.empty()); | 304 | assert(!pt_stack.empty()); |
299 | assert(pt_stack.back()==(NSURI_XRD "\tService")); | 305 | assert(pt_stack.back()==(NSURI_XRD "\tService")); |
300 | pt_stack.pop_back(); | 306 | pt_stack.pop_back(); |
301 | xrd_service = 0; | 307 | xrd_service = 0; |
302 | }else if(is_qelement(n,NSURI_XRD "\tStatus")) { | 308 | }else if(is_qelement(n,NSURI_XRD "\tStatus")) { |
303 | assert(xrd); | 309 | assert(xrd); |
304 | if(is_qelement(pt_stack.back().c_str(),n)) { | 310 | if(is_qelement(pt_stack.back().c_str(),n)) { |
305 | assert(cdata==&status_string); | 311 | assert(cdata==&status_string); |
306 | pt_stack.pop_back(); | 312 | pt_stack.pop_back(); |
307 | if(status_code!=100) | 313 | if(status_code!=100) |
308 | skipping = -1; | 314 | skipping = -1; |
309 | } | 315 | } |
310 | }else if(is_qelement(n,NSURI_XRD "\tExpires")) { | 316 | }else if(is_qelement(n,NSURI_XRD "\tExpires")) { |
311 | assert(xrd); | 317 | assert(xrd); |
312 | xrd->expires = util::w3c_to_time(cdata_buf); | 318 | xrd->expires = util::w3c_to_time(cdata_buf); |
313 | }else if((xmode&xmode_html) && is_element(n,"head")) { | 319 | }else if((xmode&xmode_html) && is_element(n,"head")) { |
314 | skipping = -1; | 320 | skipping = -1; |
315 | } | 321 | } |
316 | cdata = 0; | 322 | cdata = 0; |
317 | } | 323 | } |
318 | void character_data(const XML_Char *s,int l) { | 324 | void character_data(const XML_Char *s,int l) { |
319 | if(skipping) return; | 325 | if(skipping) return; |
320 | if(cdata) cdata->append(s,l); | 326 | if(cdata) cdata->append(s,l); |
321 | } | 327 | } |
322 | 328 | ||
323 | void html_start_element(const XML_Char *n,const XML_Char **a) { | 329 | void html_start_element(const XML_Char *n,const XML_Char **a) { |
324 | if(is_element(n,"meta")) { | 330 | if(is_element(n,"meta")) { |
325 | bool heq = false; | 331 | bool heq = false; |
326 | string l; | 332 | string l; |
327 | for(;*a;a+=2) { | 333 | for(;*a;a+=2) { |
328 | if(!( strcasecmp(a[0],"http-equiv") | 334 | if(!( strcasecmp(a[0],"http-equiv") |
329 | || strcasecmp(a[1],XRDS_HEADER) )) | 335 | || strcasecmp(a[1],XRDS_HEADER) )) |
330 | heq = true; | 336 | heq = true; |
331 | else if(!strcasecmp(a[0],"content")) | 337 | else if(!strcasecmp(a[0],"content")) |
332 | l.assign(a[1]); | 338 | l.assign(a[1]); |
333 | } | 339 | } |
334 | if(heq) | 340 | if(heq) |
335 | xrds_location = l; | 341 | xrds_location = l; |
336 | }else if(is_element(n,"link")) { | 342 | }else if(is_element(n,"link")) { |
337 | string rels; | 343 | string rels; |
338 | string href; | 344 | string href; |
339 | for(;*a;a+=2) { | 345 | for(;*a;a+=2) { |
340 | if( !strcasecmp(a[0],"rel") ) { | 346 | if( !strcasecmp(a[0],"rel") ) { |
341 | rels.assign(a[1]); | 347 | rels.assign(a[1]); |
342 | }else if( !strcasecmp(a[0],"href") ) { | 348 | }else if( !strcasecmp(a[0],"href") ) { |
343 | const char *ns = a[1]; | 349 | const char *ns = a[1]; |
344 | for(;*ns && isspace(*ns);++ns); | 350 | for(;*ns && isspace(*ns);++ns); |
345 | href.assign(ns); | 351 | href.assign(ns); |
346 | string::size_type lns=href.find_last_not_of(whitespace); | 352 | string::size_type lns=href.find_last_not_of(whitespace); |
347 | href.erase(lns+1); | 353 | href.erase(lns+1); |
348 | } | 354 | } |
349 | } | 355 | } |
350 | for(string::size_type ns=rels.find_first_not_of(whitespace); | 356 | for(string::size_type ns=rels.find_first_not_of(whitespace); |
351 | ns!=string::npos; ns=rels.find_first_not_of(whitespace,ns)) { | 357 | ns!=string::npos; ns=rels.find_first_not_of(whitespace,ns)) { |
352 | string::size_type s = rels.find_first_of(whitespace,ns); | 358 | string::size_type s = rels.find_first_of(whitespace,ns); |
353 | string rel; | 359 | string rel; |
354 | if(s==string::npos) { | 360 | if(s==string::npos) { |
355 | rel.assign(rels,ns,string::npos); | 361 | rel.assign(rels,ns,string::npos); |
356 | ns = string::npos; | 362 | ns = string::npos; |
357 | }else{ | 363 | }else{ |
358 | rel.assign(rels,ns,s-ns); | 364 | rel.assign(rels,ns,s-ns); |
359 | ns = s; | 365 | ns = s; |
360 | } | 366 | } |
361 | if(rel=="openid.server") | 367 | if(rel=="openid.server") |
362 | html_openid1.uris.add(-1,href); | 368 | html_openid1.uris.add(-1,href); |
363 | else if(rel=="openid.delegate") | 369 | else if(rel=="openid.delegate") |
364 | html_openid1.local_ids.add(-1,href); | 370 | html_openid1.local_ids.add(-1,href); |
365 | else if(rel=="openid2.provider") | 371 | else if(rel=="openid2.provider") |
366 | html_openid2.uris.add(-1,href); | 372 | html_openid2.uris.add(-1,href); |
367 | else if(rel=="openid2.local_id") | 373 | else if(rel=="openid2.local_id") |
368 | html_openid2.local_ids.add(-1,href); | 374 | html_openid2.local_ids.add(-1,href); |
369 | } | 375 | } |
370 | }else if(is_element(n,"body")) { | 376 | }else if(is_element(n,"body")) { |
371 | skipping = -1; | 377 | skipping = -1; |