• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2008 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. ``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.
24 */
25
26#if USE(PLUGIN_HOST_PROCESS)
27
28#import "HostedNetscapePluginStream.h"
29
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/WebCoreURLResponse.h>
43
44using namespace WebCore;
45
46namespace WebKit {
47
48HostedNetscapePluginStream::HostedNetscapePluginStream(NetscapePluginInstanceProxy* instance, uint32_t streamID, NSURLRequest *request)
49    : m_instance(instance)
50    , m_streamID(streamID)
51    , m_isTerminated(false)
52    , m_request(AdoptNS, [request mutableCopy])
53    , m_requestURL([request URL])
54    , m_frameLoader(0)
55{
56    if (core([instance->pluginView() webFrame])->loader()->shouldHideReferrer([request URL], core([instance->pluginView() webFrame])->loader()->outgoingReferrer()))
57        [m_request.get() _web_setHTTPReferrer:nil];
58}
59
60HostedNetscapePluginStream::HostedNetscapePluginStream(NetscapePluginInstanceProxy* instance, WebCore::FrameLoader* frameLoader)
61    : m_instance(instance)
62    , m_streamID(1)
63    , m_isTerminated(false)
64    , m_frameLoader(frameLoader)
65{
66}
67
68void HostedNetscapePluginStream::startStreamWithResponse(NSURLResponse *response)
69{
70    didReceiveResponse(0, response);
71}
72
73void HostedNetscapePluginStream::startStream(NSURL *responseURL, long long expectedContentLength, NSDate *lastModifiedDate, NSString *mimeType, NSData *headers)
74{
75    m_responseURL = responseURL;
76    m_mimeType = mimeType;
77
78    char* mimeTypeUTF8 = const_cast<char*>([mimeType UTF8String]);
79    int mimeTypeUTF8Length = mimeTypeUTF8 ? strlen (mimeTypeUTF8) + 1 : 0;
80
81    const char *url = [responseURL _web_URLCString];
82    int urlLength = url ? strlen(url) + 1 : 0;
83
84    _WKPHStartStream(m_instance->hostProxy()->port(),
85                     m_instance->pluginID(),
86                     m_streamID,
87                     const_cast<char*>(url), urlLength,
88                     expectedContentLength,
89                     [lastModifiedDate timeIntervalSince1970],
90                     mimeTypeUTF8, mimeTypeUTF8Length,
91                     const_cast<char*>(reinterpret_cast<const char*>([headers bytes])), [headers length]);
92}
93
94void HostedNetscapePluginStream::didReceiveData(WebCore::NetscapePlugInStreamLoader*, const char* bytes, int length)
95{
96    _WKPHStreamDidReceiveData(m_instance->hostProxy()->port(),
97                              m_instance->pluginID(),
98                              m_streamID,
99                              const_cast<char*>(bytes), length);
100}
101
102void HostedNetscapePluginStream::didFinishLoading(WebCore::NetscapePlugInStreamLoader*)
103{
104    _WKPHStreamDidFinishLoading(m_instance->hostProxy()->port(),
105                                m_instance->pluginID(),
106                                m_streamID);
107    m_instance->disconnectStream(this);
108}
109
110void HostedNetscapePluginStream::didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse& response)
111{
112    NSURLResponse *r = response.nsURLResponse();
113
114    NSMutableData *theHeaders = nil;
115    long long expectedContentLength = [r expectedContentLength];
116
117    if ([r isKindOfClass:[NSHTTPURLResponse class]]) {
118        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)r;
119        theHeaders = [NSMutableData dataWithCapacity:1024];
120
121        // FIXME: it would be nice to be able to get the raw HTTP header block.
122        // This includes the HTTP version, the real status text,
123        // all headers in their original order and including duplicates,
124        // and all original bytes verbatim, rather than sent through Unicode translation.
125        // Unfortunately NSHTTPURLResponse doesn't provide access at that low a level.
126
127        [theHeaders appendBytes:"HTTP " length:5];
128        char statusStr[10];
129        long statusCode = [httpResponse statusCode];
130        snprintf(statusStr, sizeof(statusStr), "%ld", statusCode);
131        [theHeaders appendBytes:statusStr length:strlen(statusStr)];
132        [theHeaders appendBytes:" OK\n" length:4];
133
134        // HACK: pass the headers through as UTF-8.
135        // This is not the intended behavior; we're supposed to pass original bytes verbatim.
136        // But we don't have the original bytes, we have NSStrings built by the URL loading system.
137        // It hopefully shouldn't matter, since RFC2616/RFC822 require ASCII-only headers,
138        // but surely someone out there is using non-ASCII characters, and hopefully UTF-8 is adequate here.
139        // It seems better than NSASCIIStringEncoding, which will lose information if non-ASCII is used.
140
141        NSDictionary *headerDict = [httpResponse allHeaderFields];
142        NSArray *keys = [[headerDict allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
143        NSEnumerator *i = [keys objectEnumerator];
144        NSString *k;
145        while ((k = [i nextObject]) != nil) {
146            NSString *v = [headerDict objectForKey:k];
147            [theHeaders appendData:[k dataUsingEncoding:NSUTF8StringEncoding]];
148            [theHeaders appendBytes:": " length:2];
149            [theHeaders appendData:[v dataUsingEncoding:NSUTF8StringEncoding]];
150            [theHeaders appendBytes:"\n" length:1];
151        }
152
153        // If the content is encoded (most likely compressed), then don't send its length to the plugin,
154        // which is only interested in the decoded length, not yet known at the moment.
155        // <rdar://problem/4470599> tracks a request for -[NSURLResponse expectedContentLength] to incorporate this logic.
156        NSString *contentEncoding = (NSString *)[[(NSHTTPURLResponse *)r allHeaderFields] objectForKey:@"Content-Encoding"];
157        if (contentEncoding && ![contentEncoding isEqualToString:@"identity"])
158            expectedContentLength = -1;
159
160        [theHeaders appendBytes:"\0" length:1];
161    }
162
163    startStream([r URL], expectedContentLength, WKGetNSURLResponseLastModifiedDate(r), [r MIMEType], theHeaders);
164}
165
166static NPReason reasonForError(NSError *error)
167{
168    if (!error)
169        return NPRES_DONE;
170
171    if ([[error domain] isEqualToString:NSURLErrorDomain] && [error code] == NSURLErrorCancelled)
172        return NPRES_USER_BREAK;
173
174    return NPRES_NETWORK_ERR;
175}
176
177void HostedNetscapePluginStream::didFail(WebCore::NetscapePlugInStreamLoader*, const WebCore::ResourceError& error)
178{
179    if (NetscapePluginHostProxy* hostProxy = m_instance->hostProxy())
180        _WKPHStreamDidFail(hostProxy->port(), m_instance->pluginID(), m_streamID, reasonForError(error));
181}
182
183bool HostedNetscapePluginStream::wantsAllStreams() const
184{
185    // FIXME: Implement.
186    return false;
187}
188
189void HostedNetscapePluginStream::start()
190{
191    ASSERT(m_request);
192    ASSERT(!m_frameLoader);
193    ASSERT(!m_loader);
194
195    m_loader = NetscapePlugInStreamLoader::create(core([m_instance->pluginView() webFrame]), this);
196    m_loader->setShouldBufferData(false);
197
198    m_loader->documentLoader()->addPlugInStreamLoader(m_loader.get());
199    m_loader->load(m_request.get());
200}
201
202void HostedNetscapePluginStream::stop()
203{
204    ASSERT(!m_frameLoader);
205
206    if (!m_loader->isDone())
207        m_loader->cancel(m_loader->cancelledError());
208}
209
210void HostedNetscapePluginStream::cancelLoad(NPReason reason)
211{
212    cancelLoad(errorForReason(reason));
213}
214
215void HostedNetscapePluginStream::cancelLoad(NSError *error)
216{
217    if (m_frameLoader) {
218        ASSERT(!m_loader);
219
220        DocumentLoader* documentLoader = m_frameLoader->activeDocumentLoader();
221        ASSERT(documentLoader);
222
223        if (documentLoader->isLoadingMainResource())
224            documentLoader->cancelMainResourceLoad(error);
225        return;
226    }
227
228    if (!m_loader->isDone())
229        m_loader->cancel(error);
230    m_instance->disconnectStream(this);
231}
232
233NSError *HostedNetscapePluginStream::pluginCancelledConnectionError() const
234{
235    return [[[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInCancelledConnection
236                                           contentURL:m_responseURL ? m_responseURL.get() : m_requestURL.get()
237                                        pluginPageURL:nil
238                                           pluginName:[[m_instance->pluginView() pluginPackage] name]
239                                             MIMEType:m_mimeType.get()] autorelease];
240}
241
242NSError *HostedNetscapePluginStream::errorForReason(NPReason reason) const
243{
244    if (reason == NPRES_DONE)
245        return nil;
246
247    if (reason == NPRES_USER_BREAK)
248        return [NSError _webKitErrorWithDomain:NSURLErrorDomain
249                                          code:NSURLErrorCancelled
250                                           URL:m_responseURL ? m_responseURL.get() : m_requestURL.get()];
251
252    return pluginCancelledConnectionError();
253}
254
255} // namespace WebKit
256
257#endif // USE(PLUGIN_HOST_PROCESS)
258
259