~ubuntu-branches/ubuntu/karmic/gears/karmic

« back to all changes in this revision

Viewing changes to gears/base/common/js_dom_element.cc

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Lesicnik
  • Date: 2009-04-30 19:15:25 UTC
  • Revision ID: james.westby@ubuntu.com-20090430191525-0790sb5wzg8ou0xb
Tags: upstream-0.5.21.0~svn3334+dfsg
ImportĀ upstreamĀ versionĀ 0.5.21.0~svn3334+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2008, Google Inc.
 
2
//
 
3
// Redistribution and use in source and binary forms, with or without
 
4
// modification, are permitted provided that the following conditions are met:
 
5
//
 
6
//  1. Redistributions of source code must retain the above copyright notice,
 
7
//     this list of conditions and the following disclaimer.
 
8
//  2. Redistributions in binary form must reproduce the above copyright notice,
 
9
//     this list of conditions and the following disclaimer in the documentation
 
10
//     and/or other materials provided with the distribution.
 
11
//  3. Neither the name of Google Inc. nor the names of its contributors may be
 
12
//     used to endorse or promote products derived from this software without
 
13
//     specific prior written permission.
 
14
//
 
15
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 
16
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 
17
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 
18
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
19
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
20
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
21
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
22
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 
23
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
24
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
25
 
 
26
#if BROWSER_FF
 
27
struct JSContext; // must declare this before including nsIJSContextStack.h
 
28
#include <gecko_sdk/include/nsCOMPtr.h>
 
29
#include <gecko_sdk/include/nsIDOMHTMLInputElement.h>
 
30
#include <gecko_sdk/include/nsIFile.h>
 
31
#include <gecko_internal/nsIJSContextStack.h>
 
32
#include <gecko_internal/nsIXPConnect.h>
 
33
#elif BROWSER_IEMOBILE
 
34
#include <webvw.h>  // For IPIEHTMLInputTextElement
 
35
#endif
 
36
 
 
37
#include "gears/base/common/js_dom_element.h"
 
38
 
 
39
#include "gears/base/common/leak_counter.h"
 
40
 
 
41
#if BROWSER_FF
 
42
#include "gears/base/firefox/ns_file_utils.h"
 
43
#endif
 
44
 
 
45
 
 
46
JsDomElement::JsDomElement()
 
47
    : is_initialized_(false) {
 
48
  LEAK_COUNTER_INCREMENT(JsDomElement);
 
49
}
 
50
 
 
51
 
 
52
JsDomElement::~JsDomElement() {
 
53
  LEAK_COUNTER_DECREMENT(JsDomElement);
 
54
}
 
55
 
 
56
 
 
57
#if BROWSER_FF
 
58
 
 
59
 
 
60
// The IIDs for nsIContent in different versions of Firefox/Gecko.
 
61
// TODO(michaeln): Add to this list as new versions show up.
 
62
 
 
63
#if BROWSER_FF3
 
64
// Firefox 3.0.x
 
65
#define NS_ICONTENT_IID_GECKO190 \
 
66
{ 0x0acd0482, 0x09a2, 0x42fd, \
 
67
  { 0xb6, 0x1b, 0x95, 0xa2, 0x01, 0x6a, 0x55, 0xd3 } }
 
68
#else
 
69
// Firefox 1.5.0.x
 
70
#define NS_ICONTENT_IID_GECKO180 \
 
71
{ 0x3fecc374, 0x2839, 0x4db3, \
 
72
  { 0x8d, 0xe8, 0x6b, 0x76, 0xd1, 0xd8, 0xe6, 0xf6 } }
 
73
// Firefox 2.0.0.x
 
74
#define NS_ICONTENT_IID_GECKO181 \
 
75
{ 0x9d059608, 0xddb0, 0x4e6a, \
 
76
  { 0x99, 0x69, 0xd2, 0xf3, 0x63, 0xa1, 0xb5, 0x57 } }
 
77
#endif  // BROWSER_FF3
 
78
 
 
79
static const nsIID kPossibleNsContentIIDs[] = {
 
80
#if BROWSER_FF3
 
81
  NS_ICONTENT_IID_GECKO190,
 
82
#else
 
83
  NS_ICONTENT_IID_GECKO180,
 
84
  NS_ICONTENT_IID_GECKO181,
 
85
#endif  // BROWSER_FF3
 
86
};
 
87
 
 
88
 
 
89
#if BROWSER_FF2
 
90
static PRBool StringBeginsWith(const nsAString &source,
 
91
                               const nsAString &substring) {
 
92
  nsAString::size_type src_len = source.Length();
 
93
  nsAString::size_type sub_len = substring.Length();
 
94
  if (sub_len > src_len)
 
95
    return PR_FALSE;
 
96
  return Substring(source, 0, sub_len).Equals(substring);
 
97
}
 
98
#endif
 
99
 
 
100
 
 
101
// This is a security measure to prevent script from spoofing DOM elements.
 
102
static bool VerifyNsContent(nsISupports *unknown) {
 
103
  if (!unknown) return false;
 
104
 
 
105
  nsresult rv = NS_OK;
 
106
  nsCOMPtr<nsIInterfaceInfoManager> iface_info_manager;
 
107
  iface_info_manager = do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID,
 
108
                                     &rv);
 
109
  if (NS_FAILED(rv) || !iface_info_manager) { return false; }
 
110
 
 
111
  // The nsIContentIID is version dependent, we test for all we know about
 
112
  for (size_t i = 0; i < ARRAYSIZE(kPossibleNsContentIIDs); ++i) {
 
113
    const nsIID *ns_content_iid = &kPossibleNsContentIIDs[i];
 
114
 
 
115
    // Paranoia, ensure that the IID we query for is either unknown to the
 
116
    // interface manager or not scriptable. The XPConnect JSWrapper
 
117
    // QueryInterface implementation will not forward to script for such
 
118
    // interfaces. In Firefox 2.0 and 1.5, nsIContent is not known by
 
119
    // the interface manager.
 
120
    nsCOMPtr<nsIInterfaceInfo> iface_info;
 
121
    rv = iface_info_manager->GetInfoForIID(ns_content_iid,
 
122
                                           getter_AddRefs(iface_info));
 
123
    if (NS_SUCCEEDED(rv) && iface_info) {
 
124
      PRBool is_scriptable = PR_TRUE;
 
125
      rv = iface_info->IsScriptable(&is_scriptable);
 
126
      if (NS_FAILED(rv) || is_scriptable) {
 
127
        continue;  // Don't test for this interface id
 
128
      }
 
129
    }
 
130
 
 
131
    // Test if our 'unknown' argument implements nsIContent,
 
132
    // a positive test indicates 'unknown' is not script based.
 
133
    nsCOMPtr<nsISupports> nscontent;
 
134
    rv = unknown->QueryInterface(*ns_content_iid,
 
135
                                 reinterpret_cast<void**>(&nscontent));
 
136
    if (NS_SUCCEEDED(rv) && nscontent) {
 
137
      return true;
 
138
    }
 
139
  }
 
140
 
 
141
  return false;
 
142
}
 
143
 
 
144
 
 
145
bool JsDomElement::InitJsDomElement(JsContextPtr context, JsToken token) {
 
146
  assert(!is_initialized_);
 
147
  assert(!dom_html_element_);
 
148
 
 
149
  if (!JSVAL_IS_OBJECT(token)) { return false; }
 
150
  JSObject *obj = JSVAL_TO_OBJECT(token);
 
151
 
 
152
  nsresult nr;
 
153
  nsCOMPtr<nsIXPConnect> xpc;
 
154
  xpc = do_GetService("@mozilla.org/js/xpc/XPConnect;1", &nr);
 
155
  if (NS_FAILED(nr)) { return false; }
 
156
 
 
157
  nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
 
158
  nr = xpc->GetWrappedNativeOfJSObject(context, obj, getter_AddRefs(wrapper));
 
159
  if (NS_FAILED(nr)) { return false; }
 
160
 
 
161
  nsCOMPtr<nsISupports> supports;
 
162
  nr = wrapper->GetNative(getter_AddRefs(supports));
 
163
  if (NS_FAILED(nr)) { return false; }
 
164
 
 
165
  // Verify unknown is a DOM HTML element
 
166
  if (!VerifyNsContent(supports)) { return false; }
 
167
  dom_html_element_ = do_QueryInterface(supports);
 
168
  if (dom_html_element_.get() == NULL) { return false; }
 
169
 
 
170
  is_initialized_ = true;
 
171
  return true;
 
172
}
 
173
 
 
174
 
 
175
 
 
176
// Security rights are gleaned from the JavaScript context.
 
177
// "UniversalFileRead" is required to get/set the file input value.
 
178
// Temporarily pushing NULL onto the JavaScript context stack lets
 
179
// the system know that native code is running and all rights are granted.
 
180
class ScopedUniversalReadRights {
 
181
 public:
 
182
  ~ScopedUniversalReadRights() {
 
183
    ReleaseRights();
 
184
  }
 
185
  bool GetRights() {
 
186
    assert(!stack_);
 
187
    stack_ = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
 
188
    if (!stack_) return false;
 
189
    stack_->Push(NULL);
 
190
    return true;
 
191
  }
 
192
  void ReleaseRights() {
 
193
    if (stack_) {
 
194
      JSContext *not_used;
 
195
      stack_->Pop(&not_used);
 
196
      stack_ = NULL;
 
197
    }
 
198
  }
 
199
 private:
 
200
  nsCOMPtr<nsIJSContextStack> stack_;
 
201
};
 
202
 
 
203
 
 
204
bool JsDomElement::GetFileInputElementValue(
 
205
    std::string16 *file_name_out) {
 
206
  assert(is_initialized_);
 
207
  nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(dom_html_element_);
 
208
  if (!input) {
 
209
    return false;
 
210
  }
 
211
 
 
212
  nsString filepath;
 
213
  {
 
214
    ScopedUniversalReadRights rights;
 
215
    if (!rights.GetRights() ||
 
216
        input->GetValue(filepath) != NS_OK) {
 
217
      return false;
 
218
    }
 
219
  }
 
220
 
 
221
  // If its really a file url, handle it differently. Gecko handles file
 
222
  // input elements in this way when submitting forms.
 
223
  if (StringBeginsWith(filepath, NS_LITERAL_STRING("file:"))) {
 
224
    nsCOMPtr<nsIFile> file;
 
225
    // Converts the URL string into the corresponding nsIFile if possible.
 
226
    NSFileUtils::GetFileFromURLSpec(filepath, getter_AddRefs(file));
 
227
    if (!file || NS_FAILED(file->GetPath(filepath))) {
 
228
      return false;
 
229
    }
 
230
  }
 
231
  
 
232
  *file_name_out = filepath.get();
 
233
  return true;
 
234
}
 
235
 
 
236
 
 
237
bool JsDomElement::SetFileInputElementValue(std::string16 &file_name) {
 
238
  assert(is_initialized_);
 
239
  nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(dom_html_element_);
 
240
  if (!input) {
 
241
    return false;
 
242
  }
 
243
 
 
244
  ScopedUniversalReadRights rights;
 
245
  if (!rights.GetRights() ||
 
246
      input->SetValue(nsString(file_name.c_str())) != NS_OK) {
 
247
    return false;
 
248
  }
 
249
  return true;
 
250
}
 
251
 
 
252
 
 
253
#elif BROWSER_IE || BROWSER_IEMOBILE
 
254
 
 
255
 
 
256
bool JsDomElement::InitJsDomElement(JsContextPtr context, JsToken token) {
 
257
  assert(!is_initialized_);
 
258
  assert(!dispatch_);
 
259
 
 
260
  if (token.vt != VT_DISPATCH) { return false; }
 
261
  IDispatch *dispatch = token.pdispVal;
 
262
 
 
263
#ifdef BROWSER_IEMOBILE
 
264
  CComQIPtr<IPIEHTMLElement> html_element(dispatch);
 
265
#else
 
266
  CComQIPtr<IHTMLElement> html_element(dispatch);
 
267
#endif
 
268
  if (!html_element) { return false; }
 
269
 
 
270
  dispatch_ = dispatch;
 
271
  is_initialized_ = true;
 
272
  return true;
 
273
}
 
274
 
 
275
 
 
276
bool JsDomElement::GetFileInputElementValue(
 
277
    std::string16 *file_name_out) {
 
278
  assert(is_initialized_);
 
279
#ifdef BROWSER_IEMOBILE
 
280
  // If it implements the IPIEHTMLInputTextElement interface, and has type
 
281
  // 'file', then accept it.
 
282
  CComQIPtr<IPIEHTMLInputTextElement> input(dispatch_);
 
283
  CComBSTR type;
 
284
  if (input && (FAILED(input->get_type(&type)) || type != L"file")) {
 
285
    input.Release();
 
286
  }
 
287
#else
 
288
  // If it implements the IHTMLInputFileElemement interface, then accept it.
 
289
  CComQIPtr<IHTMLInputFileElement> input(dispatch_);
 
290
#endif
 
291
  if (!input) {
 
292
    return false;
 
293
  }
 
294
  CComBSTR filepath;
 
295
  if (FAILED(input->get_value(&filepath))) {
 
296
    return false;
 
297
  }
 
298
  if (filepath.m_str) {
 
299
    file_name_out->assign(filepath);
 
300
  } else {
 
301
    file_name_out->clear();
 
302
  }
 
303
  return true;
 
304
}
 
305
 
 
306
 
 
307
bool JsDomElement::SetFileInputElementValue(std::string16 &file_name) {
 
308
  assert(is_initialized_);
 
309
  // On IE, we don't seem to be able to set the value of a file input element,
 
310
  // presumably because it clashes with IE's security model. Consequently,
 
311
  // any Gears code, such as LocalServer's FileSubmitter, that would normally
 
312
  // call this method also needs to implement a work-around on IE.
 
313
  return false;
 
314
}
 
315
 
 
316
 
 
317
#elif BROWSER_NPAPI
 
318
 
 
319
 
 
320
bool JsDomElement::InitJsDomElement(JsContextPtr context, JsToken token) {
 
321
  // A DOM element is at least an NPObject, but an NPObject can also be
 
322
  // an arbitrary javascript object. So this is not a strong test, just
 
323
  // a hint that the token might be a DOM element.
 
324
  assert(!is_initialized_);
 
325
  is_initialized_ = JsTokenToObject_NoCoerce(token, context,
 
326
                                             as_out_parameter(js_object_));
 
327
  return is_initialized_;
 
328
}
 
329
 
 
330
 
 
331
bool JsDomElement::GetFileInputElementValue(
 
332
    std::string16 *file_name_out) {
 
333
  // TODO(nigeltao): implement on NPAPI.
 
334
  assert(is_initialized_);
 
335
  return false;
 
336
}
 
337
 
 
338
 
 
339
bool JsDomElement::SetFileInputElementValue(std::string16 &file_name) {
 
340
  // TODO(nigeltao): implement on NPAPI.
 
341
  assert(is_initialized_);
 
342
  return false;
 
343
}
 
344
 
 
345
 
 
346
#endif