Link clicks in PDFs shouldn't send referrer headers.
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKitCocoa / PDFLinkReferrer.mm
1 /*
2  * Copyright (C) 2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27
28 #if PLATFORM(MAC)
29
30 #import "TCPServer.h"
31 #import "Test.h"
32 #import "TestNavigationDelegate.h"
33 #import "TestWKWebView.h"
34 #import "Utilities.h"
35 #import <WebKit/WKFoundation.h>
36
37 static size_t putPDFBytesCallback(void* info, void* buffer, size_t count)
38 {
39     [(NSMutableData *)info appendBytes:buffer length:count];
40     return count;
41 }
42
43 static void emptyReleaseInfoCallback(void* __nullable)
44 {
45 }
46
47 static RetainPtr<NSData> createPDFWithLinkToURL(NSURL *url)
48 {
49     auto pdfData = adoptNS([[NSMutableData alloc] init]);
50     
51     CGDataConsumerCallbacks callbacks;
52     callbacks.putBytes = (CGDataConsumerPutBytesCallback)putPDFBytesCallback;
53     callbacks.releaseConsumer = (CGDataConsumerReleaseInfoCallback)emptyReleaseInfoCallback;
54     auto consumer = adoptCF(CGDataConsumerCreate(pdfData.get(), &callbacks));
55     auto contextDictionary = adoptCF(CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
56     CGRect rectangle = CGRectMake(0, 0, 1000, 1000);
57     auto pdfContext = adoptCF(CGPDFContextCreate(consumer.get(), &rectangle, contextDictionary.get()));
58
59     auto pageDictionary = adoptCF(CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
60     auto boxData = adoptCF(CFDataCreate(NULL, (const UInt8 *)&rectangle, sizeof(CGRect)));
61     CFDictionarySetValue(pageDictionary.get(), kCGPDFContextMediaBox, boxData.get());
62     CGPDFContextBeginPage(pdfContext.get(), pageDictionary.get());
63     
64     CGContextSetRGBFillColor(pdfContext.get(), 1.0, 0.0, 0.0, 1.0);
65     CGContextSetRGBStrokeColor(pdfContext.get(), 1.0, 0.0, 0.0, 1.0);
66     CGContextFillRect(pdfContext.get(), rectangle);
67     CGPDFContextSetURLForRect(pdfContext.get(), (CFURLRef)url, rectangle);
68     CGPDFContextEndPage(pdfContext.get());
69
70     return pdfData;
71 }
72
73 TEST(WebKit, PDFLinkReferrer)
74 {
75     TestWebKitAPI::TCPServer server([] (auto socket) {
76         char readBuffer[1000];
77         memset(readBuffer, 0, 1000);
78
79         // This assumes all the data from the HTTP request is available to be read at once,
80         // which is probably an okay assumption.
81         ::read(socket, readBuffer, 999);
82
83         // Look for a referer header.
84         char* currentLine = readBuffer;
85         while (currentLine) {
86             EXPECT_NE(strncasecmp(currentLine, "referer:", 8), 0);
87             char* nextLine = strchr(currentLine, '\n');
88             currentLine = nextLine ? nextLine + 1 : 0;
89         }
90
91         const char* responseHeader =
92         "HTTP/1.1 200 OK\r\n"
93         "Content-Length: 0\r\n\r\n";
94         ::write(socket, responseHeader, strlen(responseHeader));
95     });
96
97     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
98
99     auto navigationDelegate = adoptNS([[TestNavigationDelegate alloc] init]);
100     webView.get().navigationDelegate = navigationDelegate.get();
101
102     auto *linkURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://127.0.0.1:%hu", server.port()]];
103     auto pdfData = createPDFWithLinkToURL(linkURL);
104
105     [webView loadData:pdfData.get() MIMEType:@"application/pdf" characterEncodingName:@"" baseURL:linkURL];
106     [navigationDelegate waitForDidFinishNavigation];
107
108     navigationDelegate.get().decidePolicyForNavigationAction = ^(WKNavigationAction *action, void (^decisionHandler)(WKNavigationActionPolicy)) {
109         EXPECT_NULL([action.request valueForHTTPHeaderField:@"Referer"]);
110         decisionHandler(WKNavigationActionPolicyAllow);
111     };
112     
113     [webView sendClicksAtPoint:NSMakePoint(75, 75) numberOfClicks:1];
114     [navigationDelegate waitForDidFinishNavigation];
115
116 }
117
118 #endif // PLATFORM(MAC)