Skip to content

Commit 799fe35

Browse files
Daniel HosseinianChromium LUCI CQ
authored andcommitted
[unseasoned-pdf] Extend SubmitForm() support to the Unseasoned viewer
Allow the handling of relative form URLs. Add unit tests to verify relative URL handling. Migrate SubmitForm() to PdfViewPluginBase. Add browser tests to ensure that the form submission behavior is the same with and without the Unseasoned PDF feature enabled. Bug: 1255225 Change-Id: Id1fc9c696b0ea54fd10486103a58f6c55d0103c3 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3214649 Auto-Submit: Daniel Hosseinian <dhoss@chromium.org> Commit-Queue: K. Moon <kmoon@chromium.org> Reviewed-by: K. Moon <kmoon@chromium.org> Cr-Commit-Position: refs/heads/main@{#930925}
1 parent 2f67265 commit 799fe35

File tree

10 files changed

+208
-31
lines changed

10 files changed

+208
-31
lines changed

chrome/browser/pdf/pdf_extension_test.cc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ using ::guest_view::TestGuestViewManagerFactory;
154154
using ::pdf_extension_test_util::ConvertPageCoordToScreenCoord;
155155
using ::testing::IsEmpty;
156156
using ::testing::MatchesRegex;
157+
using ::testing::StartsWith;
157158
using ::ui::AXTreeFormatter;
158159

159160
const int kNumberLoadTestParts = 10;
@@ -3701,6 +3702,54 @@ IN_PROC_BROWSER_TEST_P(PDFExtensionPrerenderTest,
37013702
ASSERT_EQ(web_contents->GetLastCommittedURL(), pdf_url);
37023703
}
37033704

3705+
class PDFExtensionSubmitFormTest : public PDFExtensionTest {
3706+
public:
3707+
void SetUpOnMainThread() override {
3708+
embedded_test_server()->RegisterRequestMonitor(base::BindLambdaForTesting(
3709+
[this](const net::test_server::HttpRequest& request) {
3710+
if (request.relative_url != "/pdf/test_endpoint")
3711+
return;
3712+
3713+
EXPECT_EQ(request.method, net::test_server::METHOD_POST);
3714+
EXPECT_THAT(request.content, StartsWith("\%FDF"));
3715+
ASSERT_TRUE(quit_closure_);
3716+
std::move(quit_closure_).Run();
3717+
}));
3718+
3719+
PDFExtensionTest::SetUpOnMainThread();
3720+
}
3721+
3722+
protected:
3723+
// Retrieves a `base::RunLoop` and saves its `QuitClosure()`. The test
3724+
// monitors HTTP requests on the IO thread, so `quit_closure_` needs to be set
3725+
// up on the UI thread before the requests can arrive.
3726+
std::unique_ptr<base::RunLoop> CreateFormSubmissionRunLoop() {
3727+
auto run_loop = std::make_unique<base::RunLoop>();
3728+
EXPECT_FALSE(quit_closure_);
3729+
quit_closure_ = run_loop->QuitClosure();
3730+
return run_loop;
3731+
}
3732+
3733+
private:
3734+
base::OnceClosure quit_closure_;
3735+
};
3736+
3737+
IN_PROC_BROWSER_TEST_P(PDFExtensionSubmitFormTest, SubmitForm) {
3738+
WebContents* guest_contents = LoadPdfGetGuestContents(
3739+
embedded_test_server()->GetURL("/pdf/submit_form.pdf"));
3740+
ASSERT_TRUE(guest_contents);
3741+
3742+
std::unique_ptr<base::RunLoop> run_loop = CreateFormSubmissionRunLoop();
3743+
3744+
// Click on the "Submit Form" button.
3745+
content::SimulateMouseClickAt(
3746+
guest_contents, blink::WebInputEvent::kNoModifiers,
3747+
blink::WebMouseEvent::Button::kLeft,
3748+
ConvertPageCoordToScreenCoord(guest_contents, {200, 200}));
3749+
3750+
run_loop->Run();
3751+
}
3752+
37043753
// TODO(crbug.com/702993): Stop testing both modes after unseasoned launches.
37053754
INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(PDFExtensionTest);
37063755
INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(PDFExtensionTestWithPartialLoading);
@@ -3721,3 +3770,4 @@ INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(PDFExtensionHitTestTest);
37213770
INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(
37223771
PDFExtensionAccessibilityNavigationTest);
37233772
INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(PDFExtensionPrerenderTest);
3773+
INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(PDFExtensionSubmitFormTest);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{{header}}
2+
{{object 1 0}} <<
3+
/Type /Catalog
4+
/Pages 2 0 R
5+
/AcroForm 4 0 R
6+
>>
7+
endobj
8+
{{object 2 0}} <<
9+
/Type /Pages
10+
/Count 1
11+
/Kids [3 0 R]
12+
>>
13+
endobj
14+
{{object 3 0}} <<
15+
/Type /Page
16+
/Parent 2 0 R
17+
/Annots [5 0 R]
18+
/MediaBox [0 0 400 400]
19+
>>
20+
endobj
21+
{{object 4 0}} <<
22+
/Fields [5 0 R]
23+
>>
24+
endobj
25+
{{object 5 0}} <<
26+
/Type /Annot
27+
/Subtype /Widget
28+
/T (SubmitFormButton)
29+
/FT /Btn
30+
/Ff 65536
31+
/Rect [150 150 250 250]
32+
/AA << /D 6 0 R >>
33+
/MK <<
34+
/BG [1.0 0.0 0.0]
35+
/CA (Submit Form)
36+
>>
37+
>>
38+
endobj
39+
{{object 6 0}} <<
40+
/Type /Action
41+
/S /JavaScript
42+
/JS (this.submitForm\('test_endpoint'\))
43+
>>
44+
endobj
45+
{{xref}}
46+
{{trailer}}
47+
{{startxref}}
48+
%%EOF
797 Bytes
Binary file not shown.

pdf/out_of_process_instance.cc

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#include "base/bind.h"
1818
#include "base/callback.h"
1919
#include "base/location.h"
20-
#include "base/logging.h"
2120
#include "base/memory/weak_ptr.h"
2221
#include "base/notreached.h"
2322
#include "base/numerics/safe_conversions.h"
@@ -715,24 +714,6 @@ std::string OutOfProcessInstance::Prompt(const std::string& question,
715714
return result.is_string() ? result.AsString() : std::string();
716715
}
717716

718-
void OutOfProcessInstance::SubmitForm(const std::string& url,
719-
const void* data,
720-
int length) {
721-
UrlRequest request;
722-
request.url = url;
723-
request.method = "POST";
724-
request.body.assign(static_cast<const char*>(data), length);
725-
726-
form_loader_ = CreateUrlLoaderInternal();
727-
form_loader_->Open(request, base::BindOnce(&OutOfProcessInstance::FormDidOpen,
728-
weak_factory_.GetWeakPtr()));
729-
}
730-
731-
void OutOfProcessInstance::FormDidOpen(int32_t result) {
732-
// TODO(crbug.com/719344): Process response.
733-
LOG_IF(ERROR, result != PP_OK) << "FormDidOpen failed: " << result;
734-
}
735-
736717
std::vector<PDFEngine::Client::SearchStringResult>
737718
OutOfProcessInstance::SearchString(const char16_t* string,
738719
const char16_t* term,

pdf/out_of_process_instance.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,6 @@ class OutOfProcessInstance : public PdfViewPluginBase,
9595
bool Confirm(const std::string& message) override;
9696
std::string Prompt(const std::string& question,
9797
const std::string& default_answer) override;
98-
void SubmitForm(const std::string& url,
99-
const void* data,
100-
int length) override;
10198
std::vector<SearchStringResult> SearchString(const char16_t* string,
10299
const char16_t* term,
103100
bool case_sensitive) override;
@@ -149,8 +146,6 @@ class OutOfProcessInstance : public PdfViewPluginBase,
149146
private:
150147
bool CanSaveEdits() const;
151148

152-
void FormDidOpen(int32_t result);
153-
154149
// The Pepper image data that is in sync with mutable_image_data().
155150
pp::ImageData pepper_image_data_;
156151

pdf/pdf_view_plugin_base.cc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "base/i18n/rtl.h"
2727
#include "base/i18n/time_formatting.h"
2828
#include "base/location.h"
29+
#include "base/logging.h"
2930
#include "base/memory/weak_ptr.h"
3031
#include "base/metrics/histogram_functions.h"
3132
#include "base/notreached.h"
@@ -69,6 +70,7 @@
6970
#include "ui/gfx/geometry/skia_conversions.h"
7071
#include "ui/gfx/geometry/vector2d.h"
7172
#include "ui/gfx/geometry/vector2d_f.h"
73+
#include "url/gurl.h"
7274

7375
namespace chrome_pdf {
7476

@@ -375,6 +377,24 @@ void PdfViewPluginBase::Print() {
375377
InvokePrintDialog();
376378
}
377379

380+
void PdfViewPluginBase::SubmitForm(const std::string& url,
381+
const void* data,
382+
int length) {
383+
// `url` might be a relative URL. Resolve it against the document's URL.
384+
GURL resolved_url = GURL(GetURL()).Resolve(url);
385+
if (!resolved_url.is_valid())
386+
return;
387+
388+
UrlRequest request;
389+
request.url = resolved_url.spec();
390+
request.method = "POST";
391+
request.body.assign(static_cast<const char*>(data), length);
392+
393+
form_loader_ = CreateUrlLoaderInternal();
394+
form_loader_->Open(
395+
request, base::BindOnce(&PdfViewPluginBase::DidFormOpen, GetWeakPtr()));
396+
}
397+
378398
std::unique_ptr<UrlLoader> PdfViewPluginBase::CreateUrlLoader() {
379399
if (full_frame_) {
380400
DidStartLoading();
@@ -1680,6 +1700,12 @@ void PdfViewPluginBase::DidOpenPreview(std::unique_ptr<UrlLoader> loader,
16801700
preview_engine_->HandleDocumentLoad(std::move(loader), GetURL());
16811701
}
16821702

1703+
void PdfViewPluginBase::DidFormOpen(int32_t result) {
1704+
// TODO(crbug.com/719344): Process response.
1705+
LOG_IF(ERROR, result != kSuccess) << "DidFormOpen failed: " << result;
1706+
form_loader_.reset();
1707+
}
1708+
16831709
void PdfViewPluginBase::OnPrintPreviewLoaded() {
16841710
// Scroll location is retained across document loads in print preview mode, so
16851711
// there's no need to override the scroll position by scrolling again.

pdf/pdf_view_plugin_base.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ class PdfViewPluginBase : public PDFEngine::Client,
116116
const std::string& subject,
117117
const std::string& body) override;
118118
void Print() override;
119+
void SubmitForm(const std::string& url,
120+
const void* data,
121+
int length) override;
119122
std::unique_ptr<UrlLoader> CreateUrlLoader() override;
120123
void DocumentLoadComplete() override;
121124
void DocumentLoadFailed() override;
@@ -484,6 +487,9 @@ class PdfViewPluginBase : public PDFEngine::Client,
484487
// Handles `LoadUrl()` result for print preview.
485488
void DidOpenPreview(std::unique_ptr<UrlLoader> loader, int32_t result);
486489

490+
// Handles `Open()` result for `form_loader_`.
491+
void DidFormOpen(int32_t result);
492+
487493
// Performs tasks necessary when the document is loaded in print preview mode.
488494
void OnPrintPreviewLoaded();
489495

@@ -619,6 +625,9 @@ class PdfViewPluginBase : public PDFEngine::Client,
619625
// Whether the document is in edit mode.
620626
bool edit_mode_ = false;
621627

628+
// Used for submitting forms.
629+
std::unique_ptr<UrlLoader> form_loader_;
630+
622631
// Assigned a value only between `PrintBegin()` and `PrintEnd()` calls.
623632
absl::optional<blink::WebPrintParams> print_params_;
624633

pdf/pdf_view_plugin_base_unittest.cc

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
#include <vector>
1111

1212
#include "base/containers/contains.h"
13+
#include "base/cxx17_backports.h"
1314
#include "base/memory/weak_ptr.h"
15+
#include "base/strings/string_piece.h"
1416
#include "base/test/icu_test_util.h"
1517
#include "base/test/values_test_util.h"
1618
#include "base/time/time.h"
@@ -40,6 +42,7 @@ using ::testing::ElementsAre;
4042
using ::testing::IsEmpty;
4143
using ::testing::Return;
4244
using ::testing::SaveArg;
45+
using ::testing::StrEq;
4346

4447
// Keep it in-sync with the `kFinalFallbackName` returned by
4548
// net::GetSuggestedFilename().
@@ -144,6 +147,8 @@ class FakePdfViewPluginBase : public PdfViewPluginBase {
144147
using PdfViewPluginBase::UpdateGeometryOnPluginRectChanged;
145148
using PdfViewPluginBase::UpdateScroll;
146149

150+
MOCK_METHOD(std::string, GetURL, (), (override));
151+
147152
MOCK_METHOD(bool, Confirm, (const std::string&), (override));
148153

149154
MOCK_METHOD(std::string,
@@ -1226,4 +1231,74 @@ TEST_F(PdfViewPluginBaseWithEngineTest, GetAccessibilityDocInfo) {
12261231
EXPECT_TRUE(doc_info.text_copyable);
12271232
}
12281233

1234+
class PdfViewPluginBaseSubmitFormTest : public PdfViewPluginBaseTest {
1235+
public:
1236+
void SubmitForm(const std::string& url,
1237+
base::StringPiece form_data = "data") {
1238+
EXPECT_CALL(fake_plugin_, CreateUrlLoaderInternal).WillOnce([this]() {
1239+
auto mock_loader = std::make_unique<testing::NiceMock<MockUrlLoader>>();
1240+
EXPECT_CALL(*mock_loader, Open).WillOnce(testing::SaveArg<0>(&request_));
1241+
return mock_loader;
1242+
});
1243+
1244+
fake_plugin_.SubmitForm(url, form_data.data(), form_data.size());
1245+
}
1246+
1247+
void SubmitFailingForm(const std::string& url) {
1248+
EXPECT_CALL(fake_plugin_, CreateUrlLoaderInternal).Times(0);
1249+
constexpr char kFormData[] = "form data";
1250+
fake_plugin_.SubmitForm(url, kFormData, base::size(kFormData));
1251+
}
1252+
1253+
protected:
1254+
UrlRequest request_;
1255+
};
1256+
1257+
TEST_F(PdfViewPluginBaseSubmitFormTest, RequestMethodAndBody) {
1258+
EXPECT_CALL(fake_plugin_, GetURL)
1259+
.WillOnce(Return("https://www.example.com/path/to/the.pdf"));
1260+
constexpr char kFormData[] = "form data";
1261+
SubmitForm(/*url=*/"", kFormData);
1262+
EXPECT_EQ(request_.method, "POST");
1263+
EXPECT_THAT(request_.body, StrEq(kFormData));
1264+
}
1265+
1266+
TEST_F(PdfViewPluginBaseSubmitFormTest, RelativeUrl) {
1267+
EXPECT_CALL(fake_plugin_, GetURL)
1268+
.WillOnce(Return("https://www.example.com/path/to/the.pdf"));
1269+
SubmitForm("relative_endpoint");
1270+
EXPECT_EQ(request_.url, "https://www.example.com/path/to/relative_endpoint");
1271+
}
1272+
1273+
TEST_F(PdfViewPluginBaseSubmitFormTest, NoRelativeUrl) {
1274+
EXPECT_CALL(fake_plugin_, GetURL)
1275+
.WillOnce(Return("https://www.example.com/path/to/the.pdf"));
1276+
SubmitForm("");
1277+
EXPECT_EQ(request_.url, "https://www.example.com/path/to/the.pdf");
1278+
}
1279+
1280+
TEST_F(PdfViewPluginBaseSubmitFormTest, AbsoluteUrl) {
1281+
EXPECT_CALL(fake_plugin_, GetURL)
1282+
.WillOnce(Return("https://a.example.com/path/to/the.pdf"));
1283+
SubmitForm("https://b.example.com/relative_endpoint");
1284+
EXPECT_EQ(request_.url, "https://b.example.com/relative_endpoint");
1285+
}
1286+
1287+
TEST_F(PdfViewPluginBaseSubmitFormTest, EmptyDocumentUrl) {
1288+
EXPECT_CALL(fake_plugin_, GetURL).WillOnce(Return(std::string()));
1289+
SubmitFailingForm("relative_endpoint");
1290+
}
1291+
1292+
TEST_F(PdfViewPluginBaseSubmitFormTest, RelativeUrlInvalidDocumentUrl) {
1293+
EXPECT_CALL(fake_plugin_, GetURL)
1294+
.WillOnce(Return(R"(https://www.%B%Ad.com/path/to/the.pdf)"));
1295+
SubmitFailingForm("relative_endpoint");
1296+
}
1297+
1298+
TEST_F(PdfViewPluginBaseSubmitFormTest, AbsoluteUrlInvalidDocumentUrl) {
1299+
EXPECT_CALL(fake_plugin_, GetURL)
1300+
.WillOnce(Return(R"(https://www.%B%Ad.com/path/to/the.pdf)"));
1301+
SubmitFailingForm("https://wwww.example.com");
1302+
}
1303+
12291304
} // namespace chrome_pdf

pdf/pdf_view_web_plugin.cc

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -670,10 +670,6 @@ std::string PdfViewWebPlugin::Prompt(const std::string& question,
670670
.Utf8();
671671
}
672672

673-
void PdfViewWebPlugin::SubmitForm(const std::string& url,
674-
const void* data,
675-
int length) {}
676-
677673
std::vector<PDFEngine::Client::SearchStringResult>
678674
PdfViewWebPlugin::SearchString(const char16_t* string,
679675
const char16_t* term,

pdf/pdf_view_web_plugin.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,6 @@ class PdfViewWebPlugin final : public PdfViewPluginBase,
228228
bool Confirm(const std::string& message) override;
229229
std::string Prompt(const std::string& question,
230230
const std::string& default_answer) override;
231-
void SubmitForm(const std::string& url,
232-
const void* data,
233-
int length) override;
234231
std::vector<SearchStringResult> SearchString(const char16_t* string,
235232
const char16_t* term,
236233
bool case_sensitive) override;

0 commit comments

Comments
 (0)