Commit 8eb0e149 authored by John Z Wu's avatar John Z Wu Committed by Commit Bot

Test invalid "translate.sendrequest" js commands

- Test URLs that do not match the security origin are not handled.
- Test invalid HTTP methods cause the request to fail.

Bug: 1110195
Change-Id: I13ab6c290c752a459e57ba4446dd133bd6d844e8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2368146Reviewed-by: default avatarDavid Roger <droger@chromium.org>
Commit-Queue: John Wu <jzw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#801100}
parent 496972ab
...@@ -33,6 +33,21 @@ ...@@ -33,6 +33,21 @@
// has been translated. // has been translated.
- (void)revertTranslation; - (void)revertTranslation;
// Returns the response to a XHR request that was proxied to the browser from
// javascript. See function __gCrWeb.translate.handleResponse.
// |URL| The original URL that was requested.
// |requestID| An ID for keeping track of inflight requests.
// |responeCode| The HTTP response code.
// |statusText| The status text associated with the response code, may be empty.
// |responseURL| The final URL from which the response originates.
// |responseText| The contents of the response.
- (void)handleTranslateResponseWithURL:(NSString*)URL
requestID:(int)requestID
responseCode:(int)responseCode
statusText:(NSString*)statusText
responseURL:(NSString*)responseURL
responseText:(NSString*)responseText;
@end @end
#endif // COMPONENTS_TRANSLATE_IOS_BROWSER_JS_TRANSLATE_MANAGER_H_ #endif // COMPONENTS_TRANSLATE_IOS_BROWSER_JS_TRANSLATE_MANAGER_H_
...@@ -56,6 +56,22 @@ ...@@ -56,6 +56,22 @@
completionHandler:nil]; completionHandler:nil];
} }
- (void)handleTranslateResponseWithURL:(NSString*)URL
requestID:(int)requestID
responseCode:(int)responseCode
statusText:(NSString*)statusText
responseURL:(NSString*)responseURL
responseText:(NSString*)responseText {
DCHECK([self hasBeenInjected]);
// Return the response details to function defined in translate_ios.js.
NSString* script = [NSString
stringWithFormat:
@"__gCrWeb.translate.handleResponse('%@', %d, %d, '%@', '%@', '%@')",
URL, requestID, responseCode, statusText, responseURL, responseText];
[self.receiver executeJavaScript:script completionHandler:nil];
}
#pragma mark - #pragma mark -
#pragma mark CRWJSInjectionManager methods #pragma mark CRWJSInjectionManager methods
......
...@@ -84,7 +84,12 @@ class TranslateController : public web::WebStateObserver { ...@@ -84,7 +84,12 @@ class TranslateController : public web::WebStateObserver {
FRIEND_TEST_ALL_PREFIXES(TranslateControllerTest, TranslationSuccess); FRIEND_TEST_ALL_PREFIXES(TranslateControllerTest, TranslationSuccess);
FRIEND_TEST_ALL_PREFIXES(TranslateControllerTest, TranslationFailure); FRIEND_TEST_ALL_PREFIXES(TranslateControllerTest, TranslationFailure);
FRIEND_TEST_ALL_PREFIXES(TranslateControllerTest, OnTranslateLoadJavascript); FRIEND_TEST_ALL_PREFIXES(TranslateControllerTest, OnTranslateLoadJavascript);
FRIEND_TEST_ALL_PREFIXES(TranslateControllerTest, OnTranslateSendRequest); FRIEND_TEST_ALL_PREFIXES(TranslateControllerTest,
OnTranslateSendRequestWithValidCommand);
FRIEND_TEST_ALL_PREFIXES(TranslateControllerTest,
OnTranslateSendRequestWithBadURL);
FRIEND_TEST_ALL_PREFIXES(TranslateControllerTest,
OnTranslateSendRequestWithBadMethod);
// Called when a JavaScript command is received. // Called when a JavaScript command is received.
bool OnJavascriptCommandReceived(const base::DictionaryValue& command, bool OnJavascriptCommandReceived(const base::DictionaryValue& command,
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "ios/web/public/navigation/navigation_context.h" #include "ios/web/public/navigation/navigation_context.h"
#include "net/base/load_flags.h" #include "net/base/load_flags.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/http/http_status_code.h"
#include "net/traffic_annotation/network_traffic_annotation.h" #include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/resource_request.h"
#include "services/network/public/mojom/url_response_head.mojom.h" #include "services/network/public/mojom/url_response_head.mojom.h"
...@@ -255,15 +256,20 @@ void TranslateController::OnRequestFetchComplete( ...@@ -255,15 +256,20 @@ void TranslateController::OnRequestFetchComplete(
std::unique_ptr<std::string> response_body) { std::unique_ptr<std::string> response_body) {
const std::unique_ptr<network::SimpleURLLoader>& url_loader = *it; const std::unique_ptr<network::SimpleURLLoader>& url_loader = *it;
// |ResponseInfo()| may be a nullptr if response is incomplete.
int response_code = 0; int response_code = 0;
std::string status_text; std::string status_text;
const network::mojom::URLResponseHead* response_head = const network::mojom::URLResponseHead* response_head =
url_loader->ResponseInfo(); url_loader->ResponseInfo();
if (response_head && response_head->headers) { int net_error_code = url_loader->NetError();
// |ResponseInfo()| may be a nullptr if response is incomplete.
if (net_error_code == net::Error::OK && response_head &&
response_head->headers) {
net::HttpResponseHeaders* headers = response_head->headers.get(); net::HttpResponseHeaders* headers = response_head->headers.get();
response_code = headers->response_code(); response_code = headers->response_code();
status_text = headers->GetStatusText(); status_text = headers->GetStatusText();
} else {
response_code = net::HttpStatusCode::HTTP_BAD_REQUEST;
} }
// Escape the returned string so it can be parsed by JSON.parse. // Escape the returned string so it can be parsed by JSON.parse.
...@@ -272,12 +278,15 @@ void TranslateController::OnRequestFetchComplete( ...@@ -272,12 +278,15 @@ void TranslateController::OnRequestFetchComplete(
base::EscapeJSONString(response_text, /*put_in_quotes=*/false, base::EscapeJSONString(response_text, /*put_in_quotes=*/false,
&escaped_response_text); &escaped_response_text);
// Return the response details to function defined in translate_ios.js. std::string final_url = url_loader->GetFinalURL().spec();
std::string script = base::StringPrintf( [js_manager_
"__gCrWeb.translate.handleResponse('%s', %d, %d, '%s', '%s', '%s')", handleTranslateResponseWithURL:base::SysUTF8ToNSString(url)
url.c_str(), request_id, response_code, status_text.c_str(), requestID:request_id
url_loader->GetFinalURL().spec().c_str(), escaped_response_text.c_str()); responseCode:response_code
web_state_->ExecuteJavaScript(base::UTF8ToUTF16(script)); statusText:base::SysUTF8ToNSString(status_text)
responseURL:base::SysUTF8ToNSString(final_url)
responseText:base::SysUTF8ToNSString(
escaped_response_text)];
request_fetchers_.erase(it); request_fetchers_.erase(it);
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "ios/web/public/test/fakes/test_browser_state.h" #include "ios/web/public/test/fakes/test_browser_state.h"
#import "ios/web/public/test/fakes/test_web_state.h" #import "ios/web/public/test/fakes/test_web_state.h"
#include "ios/web/public/test/web_task_environment.h" #include "ios/web/public/test/web_task_environment.h"
#include "net/http/http_status_code.h"
#include "testing/platform_test.h" #include "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h" #import "third_party/ocmock/OCMock/OCMock.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -173,7 +174,7 @@ TEST_F(TranslateControllerTest, TranslationFailure) { ...@@ -173,7 +174,7 @@ TEST_F(TranslateControllerTest, TranslationFailure) {
EXPECT_FALSE(error_type_ == TranslateErrors::NONE); EXPECT_FALSE(error_type_ == TranslateErrors::NONE);
} }
// Tests that OnTranslateLoadJavaScript() is called with the right paramters // Tests that OnTranslateLoadJavaScript() is called with the right parameters
// when a |translate.loadjavascript| message is received from the JS side. // when a |translate.loadjavascript| message is received from the JS side.
TEST_F(TranslateControllerTest, OnTranslateLoadJavascript) { TEST_F(TranslateControllerTest, OnTranslateLoadJavascript) {
base::DictionaryValue command; base::DictionaryValue command;
...@@ -184,9 +185,9 @@ TEST_F(TranslateControllerTest, OnTranslateLoadJavascript) { ...@@ -184,9 +185,9 @@ TEST_F(TranslateControllerTest, OnTranslateLoadJavascript) {
&fake_main_frame_)); &fake_main_frame_));
} }
// Tests that OnTranslateSendRequest() is called with the right paramters // Tests that OnTranslateSendRequest() is called with the right parameters
// when a |translate.sendrequest| message is received from the JS side. // when a |translate.sendrequest| message is received from the JS side.
TEST_F(TranslateControllerTest, OnTranslateSendRequest) { TEST_F(TranslateControllerTest, OnTranslateSendRequestWithValidCommand) {
base::DictionaryValue command; base::DictionaryValue command;
command.SetString("command", "translate.sendrequest"); command.SetString("command", "translate.sendrequest");
command.SetString("method", "POST"); command.SetString("method", "POST");
...@@ -199,4 +200,49 @@ TEST_F(TranslateControllerTest, OnTranslateSendRequest) { ...@@ -199,4 +200,49 @@ TEST_F(TranslateControllerTest, OnTranslateSendRequest) {
&fake_main_frame_)); &fake_main_frame_));
} }
// Tests that OnTranslateSendRequest() rejects a bad url contained in the
// |translate.sendrequest| message received from Javascript.
TEST_F(TranslateControllerTest, OnTranslateSendRequestWithBadURL) {
base::DictionaryValue command;
command.SetString("command", "translate.sendrequest");
command.SetString("method", "POST");
command.SetString("url", "https://badurl.example.com");
command.SetString("body", "helloworld");
command.SetDouble("requestID", 0);
EXPECT_FALSE(translate_controller_->OnJavascriptCommandReceived(
command, GURL("http://google.com"), /*interacting=*/false,
&fake_main_frame_));
}
// Tests that OnTranslateSendRequest() called with a bad method will eventually
// cause the request to fail.
TEST_F(TranslateControllerTest, OnTranslateSendRequestWithBadMethod) {
base::DictionaryValue command;
command.SetString("command", "translate.sendrequest");
command.SetString("method", "POST\r\nHost: other.example.com");
command.SetString("url",
"https://translate.googleapis.com/translate?key=abcd");
command.SetString("body", "helloworld");
command.SetDouble("requestID", 0);
[[mock_js_translate_manager_ expect]
handleTranslateResponseWithURL:
@"https://translate.googleapis.com/translate?key=abcd"
requestID:0
responseCode:net::HttpStatusCode::HTTP_BAD_REQUEST
statusText:@""
responseURL:@"https://translate.googleapis.com/"
@"translate?key=abcd"
responseText:@""];
// The command will be accepted, but a bad method should cause the request to
// fail shortly thereafter.
EXPECT_TRUE(translate_controller_->OnJavascriptCommandReceived(
command, GURL("http://google.com"), /*interacting=*/false,
&fake_main_frame_));
task_environment_.RunUntilIdle();
[mock_js_translate_manager_ verify];
}
} // namespace translate } // namespace translate
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment