| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/search_engines/template_url_parser.h" | 5 #include "chrome/browser/search_engines/template_url_parser.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 138 static void StartElementImpl(void* ctx, | 138 static void StartElementImpl(void* ctx, |
| 139 const xmlChar* name, | 139 const xmlChar* name, |
| 140 const xmlChar** atts); | 140 const xmlChar** atts); |
| 141 static void EndElementImpl(void* ctx, const xmlChar* name); | 141 static void EndElementImpl(void* ctx, const xmlChar* name); |
| 142 static void CharactersImpl(void* ctx, const xmlChar* ch, int len); | 142 static void CharactersImpl(void* ctx, const xmlChar* ch, int len); |
| 143 | 143 |
| 144 // Returns a heap-allocated TemplateURL representing the result of parsing. | 144 // Returns a heap-allocated TemplateURL representing the result of parsing. |
| 145 // This will be NULL if parsing failed or if the results were invalid for some | 145 // This will be NULL if parsing failed or if the results were invalid for some |
| 146 // reason (e.g. the resulting URL was not HTTP[S], a name wasn't supplied, | 146 // reason (e.g. the resulting URL was not HTTP[S], a name wasn't supplied, |
| 147 // etc.). | 147 // etc.). |
| 148 TemplateURL* GetTemplateURL(Profile* profile); | 148 TemplateURL* GetTemplateURL(Profile* profile, bool show_in_default_list); |
| 149 | 149 |
| 150 private: | 150 private: |
| 151 // Key is UTF8 encoded. | 151 // Key is UTF8 encoded. |
| 152 typedef std::map<std::string, ElementType> ElementNameToElementTypeMap; | 152 typedef std::map<std::string, ElementType> ElementNameToElementTypeMap; |
| 153 | 153 |
| 154 static void InitMapping(); | 154 static void InitMapping(); |
| 155 | 155 |
| 156 void ParseURL(const xmlChar** atts); | 156 void ParseURL(const xmlChar** atts); |
| 157 void ParseImage(const xmlChar** atts); | 157 void ParseImage(const xmlChar** atts); |
| 158 void ParseParam(const xmlChar** atts); | 158 void ParseParam(const xmlChar** atts); |
| 159 void ProcessURLParams(); | 159 void ProcessURLParams(); |
| 160 | 160 |
| 161 // Returns the current ElementType. | 161 // Returns the current ElementType. |
| 162 ElementType GetKnownType(); | 162 ElementType GetKnownType(); |
| 163 | 163 |
| 164 static ElementNameToElementTypeMap* kElementNameToElementTypeMap; | 164 static ElementNameToElementTypeMap* kElementNameToElementTypeMap; |
| 165 | 165 |
| 166 scoped_ptr<TemplateURL> url_; | 166 // Data that gets updated as we parse, and is converted to a TemplateURL by |
| 167 // GetTemplateURL(). |
| 168 TemplateURLData data_; |
| 167 | 169 |
| 168 std::vector<ElementType> elements_; | 170 std::vector<ElementType> elements_; |
| 169 bool image_is_valid_for_favicon_; | 171 bool image_is_valid_for_favicon_; |
| 170 | 172 |
| 171 // Character content for the current element. | 173 // Character content for the current element. |
| 172 string16 string_; | 174 string16 string_; |
| 173 | 175 |
| 174 TemplateURLParser::ParameterFilter* parameter_filter_; | 176 TemplateURLParser::ParameterFilter* parameter_filter_; |
| 175 | 177 |
| 176 // The list of parameters parsed in the Param nodes of a Url node. | 178 // The list of parameters parsed in the Param nodes of a Url node. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 190 | 192 |
| 191 DISALLOW_COPY_AND_ASSIGN(TemplateURLParsingContext); | 193 DISALLOW_COPY_AND_ASSIGN(TemplateURLParsingContext); |
| 192 }; | 194 }; |
| 193 | 195 |
| 194 // static | 196 // static |
| 195 TemplateURLParsingContext::ElementNameToElementTypeMap* | 197 TemplateURLParsingContext::ElementNameToElementTypeMap* |
| 196 TemplateURLParsingContext::kElementNameToElementTypeMap = NULL; | 198 TemplateURLParsingContext::kElementNameToElementTypeMap = NULL; |
| 197 | 199 |
| 198 TemplateURLParsingContext::TemplateURLParsingContext( | 200 TemplateURLParsingContext::TemplateURLParsingContext( |
| 199 TemplateURLParser::ParameterFilter* parameter_filter) | 201 TemplateURLParser::ParameterFilter* parameter_filter) |
| 200 : url_(new TemplateURL()), | 202 : image_is_valid_for_favicon_(false), |
| 201 image_is_valid_for_favicon_(false), | |
| 202 parameter_filter_(parameter_filter), | 203 parameter_filter_(parameter_filter), |
| 203 method_(GET), | 204 method_(GET), |
| 204 suggestion_method_(GET), | 205 suggestion_method_(GET), |
| 205 is_suggest_url_(false), | 206 is_suggest_url_(false), |
| 206 derive_image_from_url_(false) { | 207 derive_image_from_url_(false) { |
| 207 if (kElementNameToElementTypeMap == NULL) | 208 if (kElementNameToElementTypeMap == NULL) |
| 208 InitMapping(); | 209 InitMapping(); |
| 209 // When combined with proscriptions elsewhere against updating url_->url_ to | 210 // When combined with proscriptions elsewhere against updating data_->url_ to |
| 210 // the empty string, this call ensures url_->url() will never be NULL. | 211 // the empty string, this call ensures data_->url() will never be NULL. |
| 211 url_->SetURL("x"); | 212 data_.SetURL("x"); |
| 212 } | 213 } |
| 213 | 214 |
| 214 // static | 215 // static |
| 215 void TemplateURLParsingContext::StartElementImpl(void* ctx, | 216 void TemplateURLParsingContext::StartElementImpl(void* ctx, |
| 216 const xmlChar* name, | 217 const xmlChar* name, |
| 217 const xmlChar** atts) { | 218 const xmlChar** atts) { |
| 218 // Remove the namespace from |name|, ex: os:Url -> Url. | 219 // Remove the namespace from |name|, ex: os:Url -> Url. |
| 219 std::string node_name(XMLCharToString(name)); | 220 std::string node_name(XMLCharToString(name)); |
| 220 size_t index = node_name.find_first_of(":"); | 221 size_t index = node_name.find_first_of(":"); |
| 221 if (index != std::string::npos) | 222 if (index != std::string::npos) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 242 } | 243 } |
| 243 context->string_.clear(); | 244 context->string_.clear(); |
| 244 } | 245 } |
| 245 | 246 |
| 246 // static | 247 // static |
| 247 void TemplateURLParsingContext::EndElementImpl(void* ctx, const xmlChar* name) { | 248 void TemplateURLParsingContext::EndElementImpl(void* ctx, const xmlChar* name) { |
| 248 TemplateURLParsingContext* context = | 249 TemplateURLParsingContext* context = |
| 249 reinterpret_cast<TemplateURLParsingContext*>(ctx); | 250 reinterpret_cast<TemplateURLParsingContext*>(ctx); |
| 250 switch (context->GetKnownType()) { | 251 switch (context->GetKnownType()) { |
| 251 case TemplateURLParsingContext::SHORT_NAME: | 252 case TemplateURLParsingContext::SHORT_NAME: |
| 252 context->url_->short_name_ = context->string_; | 253 context->data_.short_name = context->string_; |
| 253 break; | 254 break; |
| 254 case TemplateURLParsingContext::IMAGE: { | 255 case TemplateURLParsingContext::IMAGE: { |
| 255 GURL image_url(UTF16ToUTF8(context->string_)); | 256 GURL image_url(UTF16ToUTF8(context->string_)); |
| 256 if (image_url.SchemeIs(chrome::kDataScheme)) { | 257 if (image_url.SchemeIs(chrome::kDataScheme)) { |
| 257 // TODO (jcampan): bug 1169256: when dealing with data URL, we need to | 258 // TODO (jcampan): bug 1169256: when dealing with data URL, we need to |
| 258 // decode the data URL in the renderer. For now, we'll just point to the | 259 // decode the data URL in the renderer. For now, we'll just point to the |
| 259 // favicon from the URL. | 260 // favicon from the URL. |
| 260 context->derive_image_from_url_ = true; | 261 context->derive_image_from_url_ = true; |
| 261 } else if (context->image_is_valid_for_favicon_ && image_url.is_valid() && | 262 } else if (context->image_is_valid_for_favicon_ && image_url.is_valid() && |
| 262 (image_url.SchemeIs(chrome::kHttpScheme) || | 263 (image_url.SchemeIs(chrome::kHttpScheme) || |
| 263 image_url.SchemeIs(chrome::kHttpsScheme))) { | 264 image_url.SchemeIs(chrome::kHttpsScheme))) { |
| 264 context->url_->set_favicon_url(image_url); | 265 context->data_.favicon_url = image_url; |
| 265 } | 266 } |
| 266 context->image_is_valid_for_favicon_ = false; | 267 context->image_is_valid_for_favicon_ = false; |
| 267 break; | 268 break; |
| 268 } | 269 } |
| 269 case TemplateURLParsingContext::INPUT_ENCODING: { | 270 case TemplateURLParsingContext::INPUT_ENCODING: { |
| 270 std::string input_encoding = UTF16ToASCII(context->string_); | 271 std::string input_encoding = UTF16ToASCII(context->string_); |
| 271 if (IsValidEncodingString(input_encoding)) | 272 if (IsValidEncodingString(input_encoding)) |
| 272 context->url_->input_encodings_.push_back(input_encoding); | 273 context->data_.input_encodings.push_back(input_encoding); |
| 273 break; | 274 break; |
| 274 } | 275 } |
| 275 case TemplateURLParsingContext::URL: | 276 case TemplateURLParsingContext::URL: |
| 276 context->ProcessURLParams(); | 277 context->ProcessURLParams(); |
| 277 break; | 278 break; |
| 278 default: | 279 default: |
| 279 break; | 280 break; |
| 280 } | 281 } |
| 281 context->string_.clear(); | 282 context->string_.clear(); |
| 282 context->elements_.pop_back(); | 283 context->elements_.pop_back(); |
| 283 } | 284 } |
| 284 | 285 |
| 285 // static | 286 // static |
| 286 void TemplateURLParsingContext::CharactersImpl(void* ctx, | 287 void TemplateURLParsingContext::CharactersImpl(void* ctx, |
| 287 const xmlChar* ch, | 288 const xmlChar* ch, |
| 288 int len) { | 289 int len) { |
| 289 reinterpret_cast<TemplateURLParsingContext*>(ctx)->string_ += | 290 reinterpret_cast<TemplateURLParsingContext*>(ctx)->string_ += |
| 290 UTF8ToUTF16(std::string(reinterpret_cast<const char*>(ch), len)); | 291 UTF8ToUTF16(std::string(reinterpret_cast<const char*>(ch), len)); |
| 291 } | 292 } |
| 292 | 293 |
| 293 TemplateURL* TemplateURLParsingContext::GetTemplateURL(Profile* profile) { | 294 TemplateURL* TemplateURLParsingContext::GetTemplateURL( |
| 295 Profile* profile, |
| 296 bool show_in_default_list) { |
| 294 // Basic legality checks. | 297 // Basic legality checks. |
| 295 if (url_->short_name_.empty() || !IsHTTPRef(url_->url()) || | 298 if (data_.short_name.empty() || !IsHTTPRef(data_.url()) || |
| 296 !IsHTTPRef(url_->suggestions_url())) | 299 !IsHTTPRef(data_.suggestions_url)) |
| 297 return NULL; | 300 return NULL; |
| 298 | 301 |
| 299 // If the image was a data URL, use the favicon from the search URL instead. | 302 // If the image was a data URL, use the favicon from the search URL instead. |
| 300 // (see TODO inEndElementImpl()). | 303 // (see TODO inEndElementImpl()). |
| 301 GURL url(url_->url()); | 304 GURL url(data_.url()); |
| 302 if (derive_image_from_url_ && url_->favicon_url().is_empty()) | 305 if (derive_image_from_url_ && data_.favicon_url.is_empty()) |
| 303 url_->set_favicon_url(TemplateURL::GenerateFaviconURL(url)); | 306 data_.favicon_url = TemplateURL::GenerateFaviconURL(url); |
| 304 | 307 |
| 305 // TODO(jcampan): http://b/issue?id=1196285 we do not support search engines | 308 // TODO(jcampan): http://b/issue?id=1196285 we do not support search engines |
| 306 // that use POST yet. | 309 // that use POST yet. |
| 307 if (method_ == TemplateURLParsingContext::POST) | 310 if (method_ == TemplateURLParsingContext::POST) |
| 308 return NULL; | 311 return NULL; |
| 309 if (suggestion_method_ == TemplateURLParsingContext::POST) | 312 if (suggestion_method_ == TemplateURLParsingContext::POST) |
| 310 url_->SetSuggestionsURL(std::string()); | 313 data_.suggestions_url.clear(); |
| 311 | 314 |
| 312 // Give this a keyword to facilitate tab-to-search. | 315 // Give this a keyword to facilitate tab-to-search. |
| 313 string16 keyword(TemplateURLService::GenerateKeyword(url, false)); | 316 string16 keyword(TemplateURLService::GenerateKeyword(url, false)); |
| 314 DCHECK(!keyword.empty()); | 317 DCHECK(!keyword.empty()); |
| 315 url_->set_keyword(keyword); | 318 data_.SetKeyword(keyword); |
| 316 return url_.release(); | 319 data_.show_in_default_list = show_in_default_list; |
| 320 return new TemplateURL(data_); |
| 317 } | 321 } |
| 318 | 322 |
| 319 // static | 323 // static |
| 320 void TemplateURLParsingContext::InitMapping() { | 324 void TemplateURLParsingContext::InitMapping() { |
| 321 kElementNameToElementTypeMap = new std::map<std::string, ElementType>; | 325 kElementNameToElementTypeMap = new std::map<std::string, ElementType>; |
| 322 (*kElementNameToElementTypeMap)[kURLElement] = URL; | 326 (*kElementNameToElementTypeMap)[kURLElement] = URL; |
| 323 (*kElementNameToElementTypeMap)[kParamElement] = PARAM; | 327 (*kElementNameToElementTypeMap)[kParamElement] = PARAM; |
| 324 (*kElementNameToElementTypeMap)[kShortNameElement] = SHORT_NAME; | 328 (*kElementNameToElementTypeMap)[kShortNameElement] = SHORT_NAME; |
| 325 (*kElementNameToElementTypeMap)[kImageElement] = IMAGE; | 329 (*kElementNameToElementTypeMap)[kImageElement] = IMAGE; |
| 326 (*kElementNameToElementTypeMap)[kOpenSearchDescriptionElement] = | 330 (*kElementNameToElementTypeMap)[kOpenSearchDescriptionElement] = |
| (...skipping 19 matching lines...) Expand all Loading... |
| 346 is_html_url = (type == kHTMLType); | 350 is_html_url = (type == kHTMLType); |
| 347 is_suggest_url = (type == kSuggestionType); | 351 is_suggest_url = (type == kSuggestionType); |
| 348 } else if (name == kURLTemplateAttribute) { | 352 } else if (name == kURLTemplateAttribute) { |
| 349 template_url = XMLCharToString(value); | 353 template_url = XMLCharToString(value); |
| 350 } else if (name == kParamMethodAttribute) { | 354 } else if (name == kParamMethodAttribute) { |
| 351 is_post = LowerCaseEqualsASCII(XMLCharToString(value), "post"); | 355 is_post = LowerCaseEqualsASCII(XMLCharToString(value), "post"); |
| 352 } | 356 } |
| 353 } | 357 } |
| 354 | 358 |
| 355 if (is_html_url && !template_url.empty()) { | 359 if (is_html_url && !template_url.empty()) { |
| 356 url_->SetURL(template_url); | 360 data_.SetURL(template_url); |
| 357 is_suggest_url_ = false; | 361 is_suggest_url_ = false; |
| 358 if (is_post) | 362 if (is_post) |
| 359 method_ = POST; | 363 method_ = POST; |
| 360 } else if (is_suggest_url) { | 364 } else if (is_suggest_url) { |
| 361 url_->SetSuggestionsURL(template_url); | 365 data_.suggestions_url = template_url; |
| 362 is_suggest_url_ = true; | 366 is_suggest_url_ = true; |
| 363 if (is_post) | 367 if (is_post) |
| 364 suggestion_method_ = POST; | 368 suggestion_method_ = POST; |
| 365 } | 369 } |
| 366 } | 370 } |
| 367 | 371 |
| 368 void TemplateURLParsingContext::ParseImage(const xmlChar** atts) { | 372 void TemplateURLParsingContext::ParseImage(const xmlChar** atts) { |
| 369 if (!atts) | 373 if (!atts) |
| 370 return; | 374 return; |
| 371 | 375 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 406 | 410 |
| 407 if (!key.empty() && | 411 if (!key.empty() && |
| 408 (!parameter_filter_ || parameter_filter_->KeepParameter(key, value))) | 412 (!parameter_filter_ || parameter_filter_->KeepParameter(key, value))) |
| 409 extra_params_.push_back(Param(key, value)); | 413 extra_params_.push_back(Param(key, value)); |
| 410 } | 414 } |
| 411 | 415 |
| 412 void TemplateURLParsingContext::ProcessURLParams() { | 416 void TemplateURLParsingContext::ProcessURLParams() { |
| 413 if (!parameter_filter_ && extra_params_.empty()) | 417 if (!parameter_filter_ && extra_params_.empty()) |
| 414 return; | 418 return; |
| 415 | 419 |
| 416 GURL url(is_suggest_url_ ? url_->suggestions_url() : url_->url()); | 420 GURL url(is_suggest_url_ ? data_.suggestions_url : data_.url()); |
| 417 if (url.is_empty()) | 421 if (url.is_empty()) |
| 418 return; | 422 return; |
| 419 | 423 |
| 420 // If there is a parameter filter, parse the existing URL and remove any | 424 // If there is a parameter filter, parse the existing URL and remove any |
| 421 // unwanted parameter. | 425 // unwanted parameter. |
| 422 std::string new_query; | 426 std::string new_query; |
| 423 bool modified = false; | 427 bool modified = false; |
| 424 if (parameter_filter_) { | 428 if (parameter_filter_) { |
| 425 url_parse::Component query = url.parsed_for_possibly_invalid_spec().query; | 429 url_parse::Component query = url.parsed_for_possibly_invalid_spec().query; |
| 426 url_parse::Component key, value; | 430 url_parse::Component key, value; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 444 for (std::vector<Param>::const_iterator iter(extra_params_.begin()); | 448 for (std::vector<Param>::const_iterator iter(extra_params_.begin()); |
| 445 iter != extra_params_.end(); ++iter) | 449 iter != extra_params_.end(); ++iter) |
| 446 AppendParamToQuery(iter->first, iter->second, &new_query); | 450 AppendParamToQuery(iter->first, iter->second, &new_query); |
| 447 } | 451 } |
| 448 | 452 |
| 449 if (modified) { | 453 if (modified) { |
| 450 GURL::Replacements repl; | 454 GURL::Replacements repl; |
| 451 repl.SetQueryStr(new_query); | 455 repl.SetQueryStr(new_query); |
| 452 url = url.ReplaceComponents(repl); | 456 url = url.ReplaceComponents(repl); |
| 453 if (is_suggest_url_) | 457 if (is_suggest_url_) |
| 454 url_->SetSuggestionsURL(url.spec()); | 458 data_.suggestions_url = url.spec(); |
| 455 else if (url.is_valid()) | 459 else if (url.is_valid()) |
| 456 url_->SetURL(url.spec()); | 460 data_.SetURL(url.spec()); |
| 457 } | 461 } |
| 458 } | 462 } |
| 459 | 463 |
| 460 TemplateURLParsingContext::ElementType | 464 TemplateURLParsingContext::ElementType |
| 461 TemplateURLParsingContext::GetKnownType() { | 465 TemplateURLParsingContext::GetKnownType() { |
| 462 if (elements_.size() == 2 && elements_[0] == OPEN_SEARCH_DESCRIPTION) | 466 if (elements_.size() == 2 && elements_[0] == OPEN_SEARCH_DESCRIPTION) |
| 463 return elements_[1]; | 467 return elements_[1]; |
| 464 // We only expect PARAM nodes under the URL node. | 468 // We only expect PARAM nodes under the URL node. |
| 465 return (elements_.size() == 3 && elements_[0] == OPEN_SEARCH_DESCRIPTION && | 469 return (elements_.size() == 3 && elements_[0] == OPEN_SEARCH_DESCRIPTION && |
| 466 elements_[1] == URL && elements_[2] == PARAM) ? PARAM : UNKNOWN; | 470 elements_[1] == URL && elements_[2] == PARAM) ? PARAM : UNKNOWN; |
| 467 } | 471 } |
| 468 | 472 |
| 469 | 473 |
| 470 // TemplateURLParser ---------------------------------------------------------- | 474 // TemplateURLParser ---------------------------------------------------------- |
| 471 | 475 |
| 472 // static | 476 // static |
| 473 TemplateURL* TemplateURLParser::Parse( | 477 TemplateURL* TemplateURLParser::Parse( |
| 474 Profile* profile, | 478 Profile* profile, |
| 479 bool show_in_default_list, |
| 475 const char* data, | 480 const char* data, |
| 476 size_t length, | 481 size_t length, |
| 477 TemplateURLParser::ParameterFilter* param_filter) { | 482 TemplateURLParser::ParameterFilter* param_filter) { |
| 478 // xmlSubstituteEntitiesDefault(1) makes it so that & isn't mapped to | 483 // xmlSubstituteEntitiesDefault(1) makes it so that & isn't mapped to |
| 479 // & . Unfortunately xmlSubstituteEntitiesDefault affects global state. | 484 // & . Unfortunately xmlSubstituteEntitiesDefault affects global state. |
| 480 // If this becomes problematic we'll need to provide our own entity | 485 // If this becomes problematic we'll need to provide our own entity |
| 481 // type for &, or strip out & by hand after parsing. | 486 // type for &, or strip out & by hand after parsing. |
| 482 int last_sub_entities_value = xmlSubstituteEntitiesDefault(1); | 487 int last_sub_entities_value = xmlSubstituteEntitiesDefault(1); |
| 483 TemplateURLParsingContext context(param_filter); | 488 TemplateURLParsingContext context(param_filter); |
| 484 xmlSAXHandler sax_handler; | 489 xmlSAXHandler sax_handler; |
| 485 memset(&sax_handler, 0, sizeof(sax_handler)); | 490 memset(&sax_handler, 0, sizeof(sax_handler)); |
| 486 sax_handler.startElement = &TemplateURLParsingContext::StartElementImpl; | 491 sax_handler.startElement = &TemplateURLParsingContext::StartElementImpl; |
| 487 sax_handler.endElement = &TemplateURLParsingContext::EndElementImpl; | 492 sax_handler.endElement = &TemplateURLParsingContext::EndElementImpl; |
| 488 sax_handler.characters = &TemplateURLParsingContext::CharactersImpl; | 493 sax_handler.characters = &TemplateURLParsingContext::CharactersImpl; |
| 489 xmlSAXUserParseMemory(&sax_handler, &context, data, static_cast<int>(length)); | 494 xmlSAXUserParseMemory(&sax_handler, &context, data, static_cast<int>(length)); |
| 490 xmlSubstituteEntitiesDefault(last_sub_entities_value); | 495 xmlSubstituteEntitiesDefault(last_sub_entities_value); |
| 491 | 496 |
| 492 return context.GetTemplateURL(profile); | 497 return context.GetTemplateURL(profile, show_in_default_list); |
| 493 } | 498 } |
| OLD | NEW |