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

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

Issue 1530393003: WIP: Move 'X-Frame-Options' checking to the browser. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Better. 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 2015 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/xfo_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> XFOThrottle::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 XFOThrottle(handle));
30 }
31
32 XFOThrottle::XFOThrottle(NavigationHandle* handle)
33 : NavigationThrottle(handle) {}
34
35 XFOThrottle::~XFOThrottle() {}
36
37 NavigationThrottle::ThrottleCheckResult XFOThrottle::WillProcessResponse() {
38 DCHECK(!navigation_handle()->IsInMainFrame());
39
40 NavigationHandleImpl* handle =
41 static_cast<NavigationHandleImpl*>(navigation_handle());
42
43 std::string failed_parse;
44 HeaderDisposition disposition =
45 ParseHeader(handle->GetResponseHeaders(), &failed_parse);
46 switch (disposition) {
47 case CONFLICT:
48 case INVALID:
49 ParseError(failed_parse, disposition);
50 return NavigationThrottle::BLOCK;
51
52 case DENY:
53 ConsoleError(disposition);
54 return NavigationThrottle::BLOCK;
55
56 case SAMEORIGIN: {
57 url::Origin current_origin(navigation_handle()->GetURL());
58 url::Origin top_origin =
59 handle->frame_tree_node()->frame_tree()->root()->current_origin();
60 if (top_origin.IsSameOriginWith(current_origin))
61 return NavigationThrottle::PROCEED;
62 ConsoleError(disposition);
63 return NavigationThrottle::BLOCK;
64 }
65
66 case NOT_PRESENT:
67 case ALLOWALL:
68 return NavigationThrottle::PROCEED;
69 }
70 NOTREACHED();
71 return NavigationThrottle::PROCEED;
72 }
73
74 void XFOThrottle::ParseError(const std::string& value,
75 HeaderDisposition disposition) {
76 DCHECK(disposition == CONFLICT || disposition == INVALID);
77
78 std::string message;
79 if (disposition == CONFLICT) {
80 message = base::StringPrintf(
81 "Multiple 'X-Frame-Options' headers with conflicting values "
82 "('%s') encountered when loading '%s'. Falling back to 'DENY'.",
83 value.c_str(), navigation_handle()->GetURL().spec().c_str());
84 } else {
85 message = base::StringPrintf(
86 "Invalid 'X-Frame-Options' header encountered when loading '%s': "
87 "'%s' is not a recognized directive. The header will be ignored.",
88 navigation_handle()->GetURL().spec().c_str(), value.c_str());
89 }
90
91 NavigationHandleImpl* handle =
92 static_cast<NavigationHandleImpl*>(navigation_handle());
93 // Log a console error in the parent of the current RenderFrameHost (as
94 // the current RenderFrameHost itself doesn't yet have a document).
95 handle->GetRenderFrameHost()->GetParent()->AddMessageToConsole(
96 CONSOLE_MESSAGE_LEVEL_ERROR, message);
97 }
98
99 void XFOThrottle::ConsoleError(HeaderDisposition disposition) {
100 DCHECK(disposition == DENY || disposition == SAMEORIGIN);
101 std::string message = base::StringPrintf(
102 "Refused to display '%s' in a frame because it set 'X-Frame-Options' "
103 "to '%s'",
104 navigation_handle()->GetURL().spec().c_str(),
105 disposition == DENY ? "DENY" : "SAMEORIGIN");
106
107 NavigationHandleImpl* handle =
108 static_cast<NavigationHandleImpl*>(navigation_handle());
109 // Log a console error in the parent of the current RenderFrameHost (as
110 // the current RenderFrameHost itself doesn't yet have a document).
111 handle->GetRenderFrameHost()->GetParent()->AddMessageToConsole(
112 CONSOLE_MESSAGE_LEVEL_ERROR, message);
113 }
114
115 // static
116 XFOThrottle::HeaderDisposition XFOThrottle::ParseHeader(
117 const net::HttpResponseHeaders* headers,
118 std::string* failed_parse) {
119 if (!headers)
120 return NOT_PRESENT;
121
122 void* iter = nullptr;
123 std::string value;
124 HeaderDisposition result = NOT_PRESENT;
125 while (headers->EnumerateHeader(&iter, "x-frame-options", &value)) {
126 HeaderDisposition current = INVALID;
127 base::StringPiece trimmed =
128 base::TrimWhitespaceASCII(value, base::TRIM_ALL);
129
130 if (base::LowerCaseEqualsASCII(trimmed, "deny")) {
131 current = DENY;
132 } else if (base::LowerCaseEqualsASCII(trimmed, "allowall")) {
133 current = ALLOWALL;
134 } else if (base::LowerCaseEqualsASCII(trimmed, "sameorigin")) {
135 current = SAMEORIGIN;
136 } else {
137 if (failed_parse)
138 *failed_parse = trimmed.as_string();
139 return INVALID;
140 }
141
142 if (result == NOT_PRESENT) {
143 result = current;
144 } else if (result != current) {
145 if (failed_parse)
146 *failed_parse = trimmed.as_string();
147 return CONFLICT;
148 }
149 }
150 return result;
151 }
152
153 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698