Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Side by Side Diff: content/browser/frame_host/ancestor_throttle.cc

Issue 1617043002: Introduce AncestorThrottle, which will process 'X-Frame-Options' headers. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@block-response
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/frame_host/ancestor_throttle.h"
6
7 #include "base/strings/string_util.h"
8 #include "base/strings/stringprintf.h"
9 #include "content/browser/frame_host/frame_tree.h"
10 #include "content/browser/frame_host/frame_tree_node.h"
11 #include "content/browser/frame_host/navigation_handle_impl.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/navigation_handle.h"
14 #include "content/public/browser/navigation_throttle.h"
15 #include "content/public/common/console_message_level.h"
16 #include "net/http/http_response_headers.h"
17 #include "url/origin.h"
18
19 namespace content {
20
21 // static
22 scoped_ptr<NavigationThrottle> AncestorThrottle::MaybeCreateThrottleFor(
23 NavigationHandle* handle) {
24 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
25
26 if (handle->IsInMainFrame())
27 return nullptr;
28
29 return scoped_ptr<NavigationThrottle>(new AncestorThrottle(handle));
30 }
31
32 AncestorThrottle::AncestorThrottle(NavigationHandle* handle)
33 : NavigationThrottle(handle) {}
34
35 AncestorThrottle::~AncestorThrottle() {}
36
37 NavigationThrottle::ThrottleCheckResult
38 AncestorThrottle::WillProcessResponse() {
39 DCHECK(!navigation_handle()->IsInMainFrame());
40
41 NavigationHandleImpl* handle =
42 static_cast<NavigationHandleImpl*>(navigation_handle());
43
44 std::string header_value;
45 HeaderDisposition disposition =
46 ParseHeader(handle->GetResponseHeaders(), &header_value);
47 switch (disposition) {
48 case CONFLICT:
49 ParseError(header_value, disposition);
50 return NavigationThrottle::BLOCK_RESPONSE;
51
52 case INVALID:
53 ParseError(header_value, disposition);
54 // TODO(mkwst): Consider failing here.
55 return NavigationThrottle::PROCEED;
56
57 case DENY:
58 ConsoleError(disposition);
59 return NavigationThrottle::BLOCK_RESPONSE;
60
61 case SAMEORIGIN: {
62 url::Origin current_origin(navigation_handle()->GetURL());
63 url::Origin top_origin =
64 handle->frame_tree_node()->frame_tree()->root()->current_origin();
65 if (top_origin.IsSameOriginWith(current_origin))
66 return NavigationThrottle::PROCEED;
67 ConsoleError(disposition);
68 return NavigationThrottle::BLOCK_RESPONSE;
69 }
70
71 case NONE:
72 case ALLOWALL:
73 return NavigationThrottle::PROCEED;
74 }
75 NOTREACHED();
76 return NavigationThrottle::PROCEED;
nasko 2016/02/12 23:21:40 Shouldn't we be failing closed?
Mike West 2016/04/12 20:13:30 Sure.
77 }
78
79 void AncestorThrottle::ParseError(const std::string& value,
80 HeaderDisposition disposition) {
81 DCHECK(disposition == CONFLICT || disposition == INVALID);
82
83 std::string message;
84 if (disposition == CONFLICT) {
85 message = base::StringPrintf(
86 "Refused to display '%s' in a frame because it set multiple "
87 "'X-Frame-Options' headers with conflicting values "
88 "('%s'). Falling back to 'deny'.",
89 navigation_handle()->GetURL().spec().c_str(), value.c_str());
90 } else {
91 message = base::StringPrintf(
92 "Invalid 'X-Frame-Options' header encountered when loading '%s': "
93 "'%s' is not a recognized directive. The header will be ignored.",
94 navigation_handle()->GetURL().spec().c_str(), value.c_str());
95 }
96
97 NavigationHandleImpl* handle =
98 static_cast<NavigationHandleImpl*>(navigation_handle());
nasko 2016/02/12 23:21:40 Why do you need a static cast here? GetRenderFrame
Mike West 2016/04/12 20:13:30 Done.
99 // Log a console error in the parent of the current RenderFrameHost (as
100 // the current RenderFrameHost itself doesn't yet have a document).
101 handle->GetRenderFrameHost()->GetParent()->AddMessageToConsole(
102 CONSOLE_MESSAGE_LEVEL_ERROR, message);
103 }
104
105 void AncestorThrottle::ConsoleError(HeaderDisposition disposition) {
106 DCHECK(disposition == DENY || disposition == SAMEORIGIN);
107 std::string message = base::StringPrintf(
108 "Refused to display '%s' in a frame because it set 'X-Frame-Options' "
109 "to '%s'.",
110 navigation_handle()->GetURL().spec().c_str(),
111 disposition == DENY ? "deny" : "sameorigin");
112
113 NavigationHandleImpl* handle =
114 static_cast<NavigationHandleImpl*>(navigation_handle());
nasko 2016/02/12 23:21:40 Same as above, no need for casting.
Mike West 2016/04/12 20:13:30 Done.
115 // Log a console error in the parent of the current RenderFrameHost (as
116 // the current RenderFrameHost itself doesn't yet have a document).
117 handle->GetRenderFrameHost()->GetParent()->AddMessageToConsole(
118 CONSOLE_MESSAGE_LEVEL_ERROR, message);
119 }
120
121 AncestorThrottle::HeaderDisposition AncestorThrottle::ParseHeader(
122 const net::HttpResponseHeaders* headers,
123 std::string* header_value) {
124 DCHECK(header_value);
125 if (!headers)
126 return NONE;
127
128 void* iter = nullptr;
129 std::string value;
130 HeaderDisposition result = NONE;
131 while (headers->EnumerateHeader(&iter, "x-frame-options", &value)) {
132 HeaderDisposition current = INVALID;
133
134 base::StringPiece trimmed =
135 base::TrimWhitespaceASCII(value, base::TRIM_ALL);
136 if (!header_value->empty())
137 header_value->append(", ");
138 header_value->append(trimmed.as_string());
139
140 if (base::LowerCaseEqualsASCII(trimmed, "deny"))
141 current = DENY;
142 else if (base::LowerCaseEqualsASCII(trimmed, "allowall"))
143 current = ALLOWALL;
144 else if (base::LowerCaseEqualsASCII(trimmed, "sameorigin"))
145 current = SAMEORIGIN;
146 else
147 current = INVALID;
148
149 if (result == NONE)
150 result = current;
151 else if (result != current)
152 result = CONFLICT;
153 }
154 return result;
155 }
156
157 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698