summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/frame/navigator_language.cc
blob: 061e738dfb92d55e4ef03093e15215f26d4352cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/core/frame/navigator_language.h"

#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/platform/language.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"

namespace blink {

Vector<String> ParseAndSanitize(const String& accept_languages) {
  Vector<String> languages;
  accept_languages.Split(',', languages);

  // Sanitizing tokens. We could do that more extensively but we should assume
  // that the accept languages are already sane and support BCP47. It is
  // likely a waste of time to make sure the tokens matches that spec here.
  for (size_t i = 0; i < languages.size(); ++i) {
    String& token = languages[i];
    token = token.StripWhiteSpace();
    if (token.length() >= 3 && token[2] == '_')
      token.replace(2, 1, "-");
  }

  if (languages.IsEmpty())
    languages.push_back(DefaultLanguage());

  return languages;
}

NavigatorLanguage::NavigatorLanguage(ExecutionContext* execution_context)
    : execution_context_(execution_context) {}

AtomicString NavigatorLanguage::language() {
  if (RuntimeEnabledFeatures::NavigatorLanguageInInsecureContextEnabled() ||
      (execution_context_ && execution_context_->IsSecureContext())) {
    return AtomicString(languages().front());
  }
  return AtomicString();
}

const Vector<String>& NavigatorLanguage::languages() {
  if (RuntimeEnabledFeatures::NavigatorLanguageInInsecureContextEnabled() ||
      (execution_context_ && execution_context_->IsSecureContext())) {
    EnsureUpdatedLanguage();
    return languages_;
  }
  DEFINE_STATIC_LOCAL(const Vector<String>, empty_vector, {});
  return empty_vector;
}

AtomicString NavigatorLanguage::SerializeLanguagesForClientHintHeader() {
  EnsureUpdatedLanguage();

  StringBuilder builder;
  for (size_t i = 0; i < languages_.size(); i++) {
    if (i)
      builder.Append(", ");
    builder.Append('"');
    builder.Append(languages_[i]);
    builder.Append('"');
  }
  return builder.ToAtomicString();
}

bool NavigatorLanguage::IsLanguagesDirty() const {
  return languages_dirty_;
}

void NavigatorLanguage::SetLanguagesDirty() {
  languages_dirty_ = true;
  languages_.clear();
}

void NavigatorLanguage::SetLanguagesForTesting(const String& languages) {
  languages_ = ParseAndSanitize(languages);
}

void NavigatorLanguage::EnsureUpdatedLanguage() {
  if (languages_dirty_) {
    String accept_languages_override;
    probe::ApplyAcceptLanguageOverride(execution_context_,
                                       &accept_languages_override);

    if (!accept_languages_override.IsNull()) {
      languages_ = ParseAndSanitize(accept_languages_override);
    } else {
      languages_ = ParseAndSanitize(GetAcceptLanguages());
    }

    languages_dirty_ = false;
  }
}

void NavigatorLanguage::Trace(Visitor* visitor) {
  visitor->Trace(execution_context_);
}

}  // namespace blink