2
* Copyright (C) 2008 Apple Inc. All Rights Reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
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.
13
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
#if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)
28
#import "HostedNetscapePluginStream.h"
30
#import "NetscapePluginHostProxy.h"
31
#import "NetscapePluginInstanceProxy.h"
32
#import "WebFrameInternal.h"
33
#import "WebHostedNetscapePluginView.h"
34
#import "WebKitErrorsPrivate.h"
35
#import "WebKitPluginHost.h"
36
#import "WebKitSystemInterface.h"
37
#import "WebNSURLExtras.h"
38
#import "WebNSURLRequestExtras.h"
39
#import <WebCore/DocumentLoader.h>
40
#import <WebCore/Frame.h>
41
#import <WebCore/FrameLoader.h>
42
#import <WebCore/ResourceLoadScheduler.h>
43
#import <WebCore/SecurityOrigin.h>
44
#import <WebCore/SecurityPolicy.h>
45
#import <WebCore/WebCoreURLResponse.h>
46
#import <wtf/RefCountedLeakCounter.h>
48
using namespace WebCore;
52
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, hostedNetscapePluginStreamCounter, ("HostedNetscapePluginStream"));
54
HostedNetscapePluginStream::HostedNetscapePluginStream(NetscapePluginInstanceProxy* instance, uint32_t streamID, NSURLRequest *request)
55
: m_instance(instance)
56
, m_streamID(streamID)
57
, m_request(AdoptNS, [request mutableCopy])
58
, m_requestURL([request URL])
61
String referrer = SecurityPolicy::generateReferrerHeader(core([instance->pluginView() webFrame])->document()->referrerPolicy(), [request URL], core([instance->pluginView() webFrame])->loader()->outgoingReferrer());
62
if (referrer.isEmpty())
63
[m_request.get() _web_setHTTPReferrer:nil];
65
[m_request.get() _web_setHTTPReferrer:referrer];
68
hostedNetscapePluginStreamCounter.increment();
72
HostedNetscapePluginStream::HostedNetscapePluginStream(NetscapePluginInstanceProxy* instance, WebCore::FrameLoader* frameLoader)
73
: m_instance(instance)
75
, m_frameLoader(frameLoader)
78
hostedNetscapePluginStreamCounter.increment();
82
HostedNetscapePluginStream::~HostedNetscapePluginStream()
85
hostedNetscapePluginStreamCounter.decrement();
89
void HostedNetscapePluginStream::startStreamWithResponse(NSURLResponse *response)
91
didReceiveResponse(0, response);
94
void HostedNetscapePluginStream::startStream(NSURL *responseURL, long long expectedContentLength, NSDate *lastModifiedDate, NSString *mimeType, NSData *headers)
96
m_responseURL = responseURL;
97
m_mimeType = mimeType;
99
char* mimeTypeUTF8 = const_cast<char*>([mimeType UTF8String]);
100
int mimeTypeUTF8Length = mimeTypeUTF8 ? strlen (mimeTypeUTF8) + 1 : 0;
102
const char *url = [responseURL _web_URLCString];
103
int urlLength = url ? strlen(url) + 1 : 0;
105
_WKPHStartStream(m_instance->hostProxy()->port(),
106
m_instance->pluginID(),
108
const_cast<char*>(url), urlLength,
109
expectedContentLength,
110
[lastModifiedDate timeIntervalSince1970],
111
mimeTypeUTF8, mimeTypeUTF8Length,
112
const_cast<char*>(reinterpret_cast<const char*>([headers bytes])), [headers length]);
115
void HostedNetscapePluginStream::didReceiveData(WebCore::NetscapePlugInStreamLoader*, const char* bytes, int length)
117
_WKPHStreamDidReceiveData(m_instance->hostProxy()->port(),
118
m_instance->pluginID(),
120
const_cast<char*>(bytes), length);
123
void HostedNetscapePluginStream::didFinishLoading(WebCore::NetscapePlugInStreamLoader*)
125
_WKPHStreamDidFinishLoading(m_instance->hostProxy()->port(),
126
m_instance->pluginID(),
128
m_instance->disconnectStream(this);
131
void HostedNetscapePluginStream::didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse& response)
133
NSURLResponse *r = response.nsURLResponse();
135
NSMutableData *theHeaders = nil;
136
long long expectedContentLength = [r expectedContentLength];
138
if ([r isKindOfClass:[NSHTTPURLResponse class]]) {
139
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)r;
140
theHeaders = [NSMutableData dataWithCapacity:1024];
142
// FIXME: it would be nice to be able to get the raw HTTP header block.
143
// This includes the HTTP version, the real status text,
144
// all headers in their original order and including duplicates,
145
// and all original bytes verbatim, rather than sent through Unicode translation.
146
// Unfortunately NSHTTPURLResponse doesn't provide access at that low a level.
148
[theHeaders appendBytes:"HTTP " length:5];
150
long statusCode = [httpResponse statusCode];
151
snprintf(statusStr, sizeof(statusStr), "%ld", statusCode);
152
[theHeaders appendBytes:statusStr length:strlen(statusStr)];
153
[theHeaders appendBytes:" OK\n" length:4];
155
// HACK: pass the headers through as UTF-8.
156
// This is not the intended behavior; we're supposed to pass original bytes verbatim.
157
// But we don't have the original bytes, we have NSStrings built by the URL loading system.
158
// It hopefully shouldn't matter, since RFC2616/RFC822 require ASCII-only headers,
159
// but surely someone out there is using non-ASCII characters, and hopefully UTF-8 is adequate here.
160
// It seems better than NSASCIIStringEncoding, which will lose information if non-ASCII is used.
162
NSDictionary *headerDict = [httpResponse allHeaderFields];
163
NSArray *keys = [[headerDict allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
164
NSEnumerator *i = [keys objectEnumerator];
166
while ((k = [i nextObject]) != nil) {
167
NSString *v = [headerDict objectForKey:k];
168
[theHeaders appendData:[k dataUsingEncoding:NSUTF8StringEncoding]];
169
[theHeaders appendBytes:": " length:2];
170
[theHeaders appendData:[v dataUsingEncoding:NSUTF8StringEncoding]];
171
[theHeaders appendBytes:"\n" length:1];
174
// If the content is encoded (most likely compressed), then don't send its length to the plugin,
175
// which is only interested in the decoded length, not yet known at the moment.
176
// <rdar://problem/4470599> tracks a request for -[NSURLResponse expectedContentLength] to incorporate this logic.
177
NSString *contentEncoding = (NSString *)[[(NSHTTPURLResponse *)r allHeaderFields] objectForKey:@"Content-Encoding"];
178
if (contentEncoding && ![contentEncoding isEqualToString:@"identity"])
179
expectedContentLength = -1;
181
[theHeaders appendBytes:"\0" length:1];
184
startStream([r URL], expectedContentLength, WKGetNSURLResponseLastModifiedDate(r), [r MIMEType], theHeaders);
187
NPReason HostedNetscapePluginStream::reasonForError(NSError *error)
192
if ([[error domain] isEqualToString:NSURLErrorDomain] && [error code] == NSURLErrorCancelled)
193
return NPRES_USER_BREAK;
195
return NPRES_NETWORK_ERR;
198
void HostedNetscapePluginStream::didFail(WebCore::NetscapePlugInStreamLoader*, const WebCore::ResourceError& error)
200
if (NetscapePluginHostProxy* hostProxy = m_instance->hostProxy())
201
_WKPHStreamDidFail(hostProxy->port(), m_instance->pluginID(), m_streamID, reasonForError(error));
202
m_instance->disconnectStream(this);
205
bool HostedNetscapePluginStream::wantsAllStreams() const
211
void HostedNetscapePluginStream::start()
214
ASSERT(!m_frameLoader);
217
m_loader = resourceLoadScheduler()->schedulePluginStreamLoad(core([m_instance->pluginView() webFrame]), this, m_request.get());
220
void HostedNetscapePluginStream::stop()
222
ASSERT(!m_frameLoader);
224
if (!m_loader->isDone())
225
m_loader->cancel(m_loader->cancelledError());
228
void HostedNetscapePluginStream::cancelLoad(NPReason reason)
230
cancelLoad(errorForReason(reason));
233
void HostedNetscapePluginStream::cancelLoad(NSError *error)
238
DocumentLoader* documentLoader = m_frameLoader->activeDocumentLoader();
239
if (documentLoader && documentLoader->isLoadingMainResource())
240
documentLoader->cancelMainResourceLoad(error);
244
if (!m_loader->isDone()) {
245
// Cancelling the load will disconnect the stream so there's no need to do it explicitly.
246
m_loader->cancel(error);
248
m_instance->disconnectStream(this);
251
NSError *HostedNetscapePluginStream::pluginCancelledConnectionError() const
253
return [[[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInCancelledConnection
254
contentURL:m_responseURL ? m_responseURL.get() : m_requestURL.get()
256
pluginName:[[m_instance->pluginView() pluginPackage] pluginInfo].name
257
MIMEType:m_mimeType.get()] autorelease];
260
NSError *HostedNetscapePluginStream::errorForReason(NPReason reason) const
262
if (reason == NPRES_DONE)
265
if (reason == NPRES_USER_BREAK)
266
return [NSError _webKitErrorWithDomain:NSURLErrorDomain
267
code:NSURLErrorCancelled
268
URL:m_responseURL ? m_responseURL.get() : m_requestURL.get()];
270
return pluginCancelledConnectionError();
273
} // namespace WebKit
275
#endif // USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)