| /* |
| * Copyright 2011 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // Author: nforman@google.com (Naomi Forman) |
| // |
| // Implements the convert_meta_tags filter, which creates a |
| // response header for http-equiv meta tags. |
| |
| #include "net/instaweb/rewriter/public/meta_tag_filter.h" |
| |
| #include "net/instaweb/rewriter/public/rewrite_driver.h" |
| #include "pagespeed/kernel/base/statistics.h" |
| #include "pagespeed/kernel/base/string.h" |
| #include "pagespeed/kernel/base/string_util.h" |
| #include "pagespeed/kernel/html/html_element.h" |
| #include "pagespeed/kernel/html/html_name.h" |
| #include "pagespeed/kernel/http/content_type.h" |
| #include "pagespeed/kernel/http/response_headers.h" |
| |
| namespace { |
| |
| // Statistics variable for number of tags converted to headers. |
| const char kConvertedMetaTags[] = "converted_meta_tags"; |
| |
| } // namespace |
| |
| namespace net_instaweb { |
| |
| MetaTagFilter::MetaTagFilter(RewriteDriver* rewrite_driver) |
| : CommonFilter(rewrite_driver), |
| response_headers_(NULL) { |
| Statistics* stats = driver()->statistics(); |
| converted_meta_tag_count_ = stats->GetVariable(kConvertedMetaTags); |
| } |
| |
| void MetaTagFilter::InitStats(Statistics* stats) { |
| stats->AddVariable(kConvertedMetaTags); |
| } |
| |
| MetaTagFilter::~MetaTagFilter() {} |
| |
| void MetaTagFilter::StartDocumentImpl() { |
| // This pointer will be nulled at first Flush to guarantee that we don't |
| // write it after that (won't work). |
| response_headers_ = driver()->mutable_response_headers(); |
| } |
| |
| |
| void MetaTagFilter::EndElementImpl(HtmlElement* element) { |
| // If response_headers_ are null, they got reset due to a flush, so don't |
| // try to convert any tags into response_headers_ (which were already |
| // finalized). Also don't add meta tags to response_headers_ if they're |
| // inside a noscript tag. |
| if (response_headers_ == NULL || noscript_element() != NULL || |
| element->keyword() != HtmlName::kMeta) { |
| return; |
| } |
| if (ExtractAndUpdateMetaTagDetails(element, response_headers_)) { |
| converted_meta_tag_count_->Add(1); |
| } |
| } |
| |
| bool MetaTagFilter::ExtractAndUpdateMetaTagDetails( |
| HtmlElement* element, |
| ResponseHeaders* response_headers) { |
| if (response_headers == NULL) { |
| return false; |
| } |
| GoogleString content, mime_type, charset; |
| |
| if (ExtractMetaTagDetails(*element, response_headers, |
| &content, &mime_type, &charset)) { |
| if (!content.empty()) { |
| // Yes content => it has http-equiv and content attributes, |
| // and a mime_type and/or a charset, but we need a mime_type. |
| if (!mime_type.empty()) { |
| const ContentType* type = MimeTypeToContentType(mime_type); |
| // We only want to propagate the charset for HTML; |
| // XHTML is forced to UTF-8 anyway and we really don't want to propagate |
| // an XHTML type in cases where Apache is unsure just to propagate |
| // a charset that's not supposed to take any effect. |
| if (type != NULL && type->type() == ContentType::kHtml) { |
| if (response_headers->MergeContentType(content)) { |
| return true; |
| } |
| } |
| } |
| } else { |
| // No content => it has a charset attribute (and no mime_type). |
| GoogleString type = StrCat("; charset=", charset); |
| if (response_headers->MergeContentType(type)) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| void MetaTagFilter::Flush() { |
| response_headers_ = NULL; |
| } |
| |
| } // namespace net_instaweb |