~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/extensions/webservices/security/src/nsWebScriptsAccess.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Mozilla Public License Version
 
6
 * 1.1 (the "License"); you may not use this file except in compliance with
 
7
 * the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/MPL/
 
9
 *
 
10
 * Software distributed under the License is distributed on an "AS IS" basis,
 
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
12
 * for the specific language governing rights and limitations under the
 
13
 * License.
 
14
 *
 
15
 * The Original Code is the web scripts access security code.
 
16
 *
 
17
 * The Initial Developer of the Original Code is
 
18
 * Netscape Communications Corporation.
 
19
 * Portions created by the Initial Developer are Copyright (C) 2002
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s): Harish Dhurvasula <harishd@netscape.com>
 
23
 *
 
24
 * Alternatively, the contents of this file may be used under the terms of
 
25
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
26
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
27
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
28
 * of those above. If you wish to allow use of your version of this file only
 
29
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
30
 * use your version of this file under the terms of the MPL, indicate your
 
31
 * decision by deleting the provisions above and replace them with the notice
 
32
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
33
 * the provisions above, a recipient may use your version of this file under
 
34
 * the terms of any one of the MPL, the GPL or the LGPL.
 
35
 *
 
36
 * ***** END LICENSE BLOCK ***** */
 
37
 
 
38
#include "nsWebScriptsAccess.h"
 
39
#include "nsString.h"
 
40
#include "nsAutoPtr.h"
 
41
#include "nsIDOMDocument.h"
 
42
#include "nsIDOMElement.h"
 
43
#include "nsIDOMNodeList.h"
 
44
#include "nsIDOMAttr.h"
 
45
#include "nsIDOMNamedNodeMap.h"
 
46
#include "nsIPrincipal.h"
 
47
#include "nsIURL.h"
 
48
#include "nsReadableUtils.h"
 
49
#include "nsIHttpChannel.h"
 
50
#include "nsNetUtil.h"
 
51
#include "nsIXPConnect.h"
 
52
#include "jsapi.h"
 
53
 
 
54
#include "nsISOAPCall.h"
 
55
#include "nsISOAPEncoding.h"
 
56
#include "nsISOAPResponse.h"
 
57
#include "nsISOAPFault.h"
 
58
#include "nsISOAPParameter.h"
 
59
#include "nsISOAPBlock.h"
 
60
#include "nsIVariant.h"
 
61
#include "nsIPrefService.h"
 
62
#include "nsIPrefBranchInternal.h"
 
63
#include "nsIJSContextStack.h"
 
64
 
 
65
#define WSA_GRANT_ACCESS_TO_ALL     (1 << 0)
 
66
#define WSA_FILE_NOT_FOUND          (1 << 1)
 
67
#define WSA_FILE_DELEGATED          (1 << 2)
 
68
#define SERVICE_LISTED_PUBLIC       (1 << 3)
 
69
#define HAS_MASTER_SERVICE_DECISION (1 << 4)
 
70
 
 
71
static PRBool PR_CALLBACK 
 
72
FreeEntries(nsHashKey *aKey, void *aData, void* aClosure)
 
73
{
 
74
  AccessInfoEntry* entry = NS_REINTERPRET_CAST(AccessInfoEntry*, aData);
 
75
  delete entry;
 
76
  return PR_TRUE;
 
77
}
 
78
 
 
79
NS_IMPL_ISUPPORTS1(nsWebScriptsAccess, 
 
80
                   nsIWebScriptsAccessService)
 
81
 
 
82
nsWebScriptsAccess::nsWebScriptsAccess()
 
83
  : NS_LITERAL_STRING_INIT(kNamespace2002, "http://www.mozilla.org/2002/soap/security")
 
84
  , NS_LITERAL_STRING_INIT(kWebScriptAccessTag, "webScriptAccess")
 
85
  , NS_LITERAL_STRING_INIT(kDelegateTag, "delegate")
 
86
  , NS_LITERAL_STRING_INIT(kAllowTag, "allow")
 
87
  , NS_LITERAL_STRING_INIT(kTypeAttr, "type")
 
88
  , NS_LITERAL_STRING_INIT(kFromAttr, "from")
 
89
  , NS_LITERAL_STRING_INIT(kAny, "any")
 
90
  , NS_LITERAL_STRING_INIT(kIsServicePublic, "isServicePublic")
 
91
{
 
92
}
 
93
 
 
94
nsWebScriptsAccess::~nsWebScriptsAccess()
 
95
{
 
96
  mAccessInfoTable.Enumerate(FreeEntries, this);
 
97
}
 
98
 
 
99
NS_IMETHODIMP 
 
100
nsWebScriptsAccess::CanAccess(nsIURI* aTransportURI,
 
101
                              const nsAString& aRequestType,
 
102
                              PRBool* aAccessGranted)
 
103
{
 
104
  *aAccessGranted = PR_FALSE;
 
105
  NS_ENSURE_ARG_POINTER(aTransportURI);
 
106
 
 
107
  nsresult rv;
 
108
  if (!mSecurityManager) {
 
109
    mSecurityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
 
110
    NS_ENSURE_SUCCESS(rv, rv);
 
111
  }
 
112
   
 
113
  rv =
 
114
    mSecurityManager->IsCapabilityEnabled("UniversalBrowserRead", 
 
115
                                          aAccessGranted);
 
116
  if (NS_FAILED(rv) || *aAccessGranted)
 
117
    return rv;
 
118
  
 
119
  mServiceURI = aTransportURI;
 
120
 
 
121
  nsXPIDLCString path;
 
122
  aTransportURI->GetPrePath(path);
 
123
  path += '/';
 
124
 
 
125
  AccessInfoEntry* entry = 0;
 
126
  rv = GetAccessInfoEntry(path, &entry);
 
127
  if (!entry) {
 
128
    rv = mSecurityManager->CheckSameOrigin(0, aTransportURI);
 
129
    if (NS_SUCCEEDED(rv)) {
 
130
      // script security manager has granted access
 
131
      *aAccessGranted = PR_TRUE;
 
132
      return rv;
 
133
    }
 
134
    else {
 
135
      // Script security manager has denied access and has set an
 
136
      // exception. Clear the exception and fall back on the new
 
137
      // security model's decision.
 
138
      nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID()));
 
139
      if (xpc) {
 
140
        nsCOMPtr<nsIXPCNativeCallContext> cc;
 
141
        xpc->GetCurrentNativeCallContext(getter_AddRefs(cc));
 
142
        if (cc) {
 
143
          JSContext* cx;
 
144
          rv = cc->GetJSContext(&cx);
 
145
          NS_ENSURE_SUCCESS(rv, rv);
 
146
 
 
147
          JS_ClearPendingException(cx);
 
148
          cc->SetExceptionWasThrown(PR_FALSE);
 
149
        }
 
150
      }
 
151
    }
 
152
 
 
153
    rv = CreateEntry(path, PR_FALSE, &entry);
 
154
    NS_ENSURE_SUCCESS(rv, rv);
 
155
  }
 
156
 
 
157
  return CheckAccess(entry, aRequestType, aAccessGranted);
 
158
}
 
159
 
 
160
NS_IMETHODIMP 
 
161
nsWebScriptsAccess::InvalidateCache(const char* aTransportURI)
 
162
{
 
163
  if (aTransportURI) {
 
164
    nsCStringKey key(aTransportURI);
 
165
    if (mAccessInfoTable.Exists(&key)) {
 
166
      AccessInfoEntry* entry = 
 
167
        NS_REINTERPRET_CAST(AccessInfoEntry*, mAccessInfoTable.Remove(&key));
 
168
      delete entry;
 
169
    }
 
170
  }
 
171
  else {
 
172
    // If a URI is not specified then we clear the entire cache.
 
173
    mAccessInfoTable.Enumerate(FreeEntries, this);
 
174
  }
 
175
  return NS_OK;
 
176
}
 
177
 
 
178
nsresult 
 
179
nsWebScriptsAccess::GetAccessInfoEntry(const char* aKey,
 
180
                                       AccessInfoEntry** aEntry)
 
181
{
 
182
  nsCStringKey key(aKey);
 
183
 
 
184
  *aEntry = NS_REINTERPRET_CAST(AccessInfoEntry*, mAccessInfoTable.Get(&key));
 
185
  if (*aEntry  && ((*aEntry)->mFlags & WSA_FILE_DELEGATED)) {
 
186
    nsresult rv;
 
187
    nsCOMPtr<nsIURL> url(do_QueryInterface(mServiceURI, &rv));
 
188
    NS_ENSURE_SUCCESS(rv, rv);
 
189
  
 
190
    nsCAutoString path;
 
191
    url->GetPrePath(path);
 
192
    nsCAutoString directory;
 
193
    url->GetDirectory(directory);
 
194
    path += directory;
 
195
 
 
196
    return GetAccessInfoEntry(path.get(), aEntry);
 
197
  }
 
198
  return NS_OK;
 
199
}
 
200
 
 
201
nsresult 
 
202
nsWebScriptsAccess::GetDocument(const nsACString& aDeclFilePath,
 
203
                                nsIDOMDocument** aDocument)
 
204
{
 
205
  nsresult rv = NS_OK;
 
206
  
 
207
  if (!mRequest) {
 
208
    mRequest = do_CreateInstance(NS_XMLHTTPREQUEST_CONTRACTID, &rv);
 
209
    NS_ENSURE_SUCCESS(rv, rv);
 
210
  }
 
211
 
 
212
  const nsAString& empty = EmptyString();
 
213
  rv = mRequest->OpenRequest(NS_LITERAL_CSTRING("GET"), aDeclFilePath,
 
214
                             PR_FALSE, empty, empty);
 
215
  NS_ENSURE_SUCCESS(rv, rv);
 
216
    
 
217
  rv = mRequest->OverrideMimeType(NS_LITERAL_CSTRING("text/xml"));
 
218
  NS_ENSURE_SUCCESS(rv, rv);
 
219
 
 
220
  rv = mRequest->Send(0);
 
221
  NS_ENSURE_SUCCESS(rv, rv);
 
222
 
 
223
  nsCOMPtr<nsIChannel> channel;
 
224
  mRequest->GetChannel(getter_AddRefs(channel));
 
225
  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel, &rv));
 
226
  NS_ENSURE_TRUE(httpChannel, rv);
 
227
 
 
228
  PRBool succeeded;
 
229
  httpChannel->GetRequestSucceeded(&succeeded);
 
230
 
 
231
  if (succeeded) {
 
232
    rv = mRequest->GetResponseXML(aDocument);
 
233
    NS_ENSURE_SUCCESS(rv, rv);
 
234
  }
 
235
 
 
236
  return rv;
 
237
}
 
238
 
 
239
nsresult
 
240
nsWebScriptsAccess::GetCodebaseURI(nsIURI** aCodebase)
 
241
{
 
242
  nsresult rv = NS_OK;
 
243
 
 
244
  if (!mSecurityManager) {
 
245
    mSecurityManager = 
 
246
      do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
 
247
    NS_ENSURE_SUCCESS(rv, rv);
 
248
  }
 
249
 
 
250
  nsCOMPtr<nsIPrincipal> principal;
 
251
  rv = mSecurityManager->GetSubjectPrincipal(getter_AddRefs(principal));
 
252
  NS_ENSURE_SUCCESS(rv, rv);
 
253
  
 
254
  return principal->GetURI(aCodebase);
 
255
}
 
256
 
 
257
nsresult 
 
258
nsWebScriptsAccess::CreateEntry(const char* aKey,
 
259
                                const PRBool aIsDelegated,
 
260
                                AccessInfoEntry** aEntry)
 
261
{
 
262
  NS_ENSURE_ARG_POINTER(aEntry);
 
263
  *aEntry = nsnull;
 
264
  // create an entry by loading the declaration file (
 
265
  // web-scripts-access.xml ) and extracting access information from
 
266
  // it. Record the extracted info. for this session
 
267
  nsCOMPtr<nsIDOMDocument> document;
 
268
  nsresult rv = 
 
269
    GetDocument(nsDependentCString(aKey) +
 
270
                NS_LITERAL_CSTRING("web-scripts-access.xml"),
 
271
                getter_AddRefs(document));
 
272
  NS_ENSURE_SUCCESS(rv, rv);
 
273
  if (document) {
 
274
    // Create an entry by extracting access information from the document.
 
275
    rv = CreateEntry(document, aIsDelegated, aEntry);
 
276
    NS_ENSURE_SUCCESS(rv, rv);
 
277
 
 
278
    // If the document is invalid then an entry will not be created.
 
279
    if (!*aEntry)
 
280
      return NS_OK;
 
281
  }
 
282
  else {
 
283
    rv = CreateEntry(WSA_FILE_NOT_FOUND, aEntry);
 
284
    NS_ENSURE_SUCCESS(rv, rv);
 
285
  }
 
286
  nsCStringKey key(aKey);
 
287
  mAccessInfoTable.Put(&key, *aEntry);
 
288
 
 
289
  NS_ASSERTION(*aEntry, "unexpected: access info entry is null!");
 
290
  if (*aEntry  && ((*aEntry)->mFlags & WSA_FILE_DELEGATED))
 
291
    rv = CreateDelegatedEntry(aEntry);
 
292
  return rv;
 
293
}
 
294
 
 
295
nsresult 
 
296
nsWebScriptsAccess::CreateEntry(nsIDOMDocument* aDocument,
 
297
                                const PRBool aIsDelegated,
 
298
                                AccessInfoEntry** aEntry)
 
299
{
 
300
  NS_ENSURE_ARG_POINTER(aDocument);
 
301
  NS_ENSURE_ARG_POINTER(aEntry);
 
302
  *aEntry = nsnull;
 
303
  
 
304
  PRBool valid;
 
305
  nsresult rv = ValidateDocument(aDocument, &valid);
 
306
  NS_ENSURE_SUCCESS(rv, rv);
 
307
 
 
308
  if (!valid) {
 
309
    return NS_OK; // XXX should I return an error instead ?
 
310
  }
 
311
 
 
312
  if (!aIsDelegated) {
 
313
    nsCOMPtr<nsIDOMNodeList> delegateList; 
 
314
    rv = aDocument->GetElementsByTagNameNS(kNamespace2002, kDelegateTag, 
 
315
                                           getter_AddRefs(delegateList));
 
316
    NS_ENSURE_TRUE(delegateList, rv);
 
317
    nsCOMPtr<nsIDOMNode> node;
 
318
    delegateList->Item(0, getter_AddRefs(node));
 
319
    if (node)
 
320
      return CreateEntry(WSA_FILE_DELEGATED, aEntry);
 
321
  }
 
322
 
 
323
  nsCOMPtr<nsIDOMNodeList> allowList;
 
324
  rv = aDocument->GetElementsByTagNameNS(kNamespace2002, kAllowTag, 
 
325
                                         getter_AddRefs(allowList));
 
326
  NS_ENSURE_TRUE(allowList, rv);
 
327
 
 
328
  PRUint32 count;
 
329
  allowList->GetLength(&count);
 
330
  if (count) {
 
331
    rv = CreateEntry(allowList, aEntry);
 
332
  }
 
333
  else {
 
334
    // Since there are no ALLOW elements present grant access to all.
 
335
    rv = CreateEntry(WSA_GRANT_ACCESS_TO_ALL, aEntry);
 
336
  }
 
337
 
 
338
  return rv;
 
339
}
 
340
 
 
341
nsresult
 
342
nsWebScriptsAccess::CreateEntry(const PRInt32 aFlags, 
 
343
                                AccessInfoEntry** aEntry)
 
344
{
 
345
  *aEntry = new AccessInfoEntry(aFlags);
 
346
  NS_ENSURE_TRUE(*aEntry, NS_ERROR_OUT_OF_MEMORY);
 
347
 
 
348
  return NS_OK;
 
349
}
 
350
 
 
351
nsresult
 
352
nsWebScriptsAccess::CreateEntry(nsIDOMNodeList* aAllowList,
 
353
                                AccessInfoEntry** aEntry)
 
354
{
 
355
  NS_ENSURE_ARG_POINTER(aAllowList);
 
356
  NS_ENSURE_ARG_POINTER(aEntry);
 
357
  *aEntry = nsnull;
 
358
 
 
359
  nsAutoPtr<AccessInfoEntry> entry(new AccessInfoEntry());
 
360
  NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
 
361
 
 
362
  PRUint32 count;
 
363
  aAllowList->GetLength(&count);
 
364
 
 
365
  PRUint32 index; 
 
366
  nsCOMPtr<nsIDOMNode> node;
 
367
  nsAutoString type, from;
 
368
  for (index = 0; index < count; index++) {
 
369
    aAllowList->Item(index, getter_AddRefs(node));
 
370
    NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
 
371
     
 
372
    nsCOMPtr<nsIDOMElement> element(do_QueryInterface(node));
 
373
    element->GetAttribute(kTypeAttr, type);
 
374
    element->GetAttribute(kFromAttr, from);
 
375
 
 
376
    PRBool found_type = !type.IsEmpty();
 
377
    PRBool found_from = !from.IsEmpty();
 
378
 
 
379
    if (!found_type && !found_from) {
 
380
      // Minor optimization - If the "type" and "from"
 
381
      // attributes aren't present then no need to check
 
382
      // for attributes in other "allow" elements because
 
383
      // access will be granted to all regardless.
 
384
      entry->mFlags |= WSA_GRANT_ACCESS_TO_ALL;
 
385
      break;
 
386
    }
 
387
 
 
388
    nsAutoPtr<AccessInfo> access_info(new AccessInfo());
 
389
    NS_ENSURE_TRUE(access_info, NS_ERROR_OUT_OF_MEMORY);
 
390
    
 
391
    if (found_type) {
 
392
      access_info->mType = ToNewUnicode(type);
 
393
      NS_ENSURE_TRUE(access_info->mType, NS_ERROR_OUT_OF_MEMORY);
 
394
    }
 
395
 
 
396
    if (found_from) {
 
397
      access_info->mFrom = ToNewUnicode(from);
 
398
      NS_ENSURE_TRUE(access_info->mFrom, NS_ERROR_OUT_OF_MEMORY);
 
399
    }
 
400
 
 
401
    entry->mInfoArray.AppendElement(access_info.forget());
 
402
    
 
403
    type.Truncate();
 
404
    from.Truncate();
 
405
  }
 
406
 
 
407
  *aEntry = entry.forget();
 
408
 
 
409
  return NS_OK;
 
410
}
 
411
 
 
412
nsresult
 
413
nsWebScriptsAccess::CreateDelegatedEntry(AccessInfoEntry** aEntry)
 
414
{
 
415
  NS_ENSURE_ARG_POINTER(aEntry);
 
416
  *aEntry = nsnull;
 
417
  
 
418
  nsresult rv;
 
419
  nsCOMPtr<nsIURL> url(do_QueryInterface(mServiceURI, &rv));
 
420
  NS_ENSURE_SUCCESS(rv, rv);
 
421
  
 
422
  nsCAutoString path;
 
423
  url->GetPrePath(path);
 
424
  nsCAutoString directory;
 
425
  url->GetDirectory(directory);
 
426
  path += directory;
 
427
 
 
428
  return CreateEntry(path.get(), PR_TRUE, aEntry);
 
429
}
 
430
 
 
431
nsresult
 
432
nsWebScriptsAccess::CheckAccess(AccessInfoEntry* aEntry,
 
433
                                const nsAString& aRequestType, 
 
434
                                PRBool* aAccessGranted)
 
435
{
 
436
#ifdef DEBUG
 
437
  static PRBool verified = PR_FALSE;
 
438
  if (!verified) {
 
439
    verified = PR_TRUE;
 
440
    nsWSAUtils::VerifyIsEqual();
 
441
  }
 
442
#endif
 
443
 
 
444
  *aAccessGranted = PR_FALSE;
 
445
  NS_ENSURE_ARG_POINTER(aEntry);
 
446
 
 
447
  nsresult rv = NS_OK;
 
448
  if (aEntry->mFlags & WSA_FILE_NOT_FOUND) {
 
449
    if (aEntry->mFlags & HAS_MASTER_SERVICE_DECISION) {
 
450
      if (aEntry->mFlags & SERVICE_LISTED_PUBLIC)
 
451
         *aAccessGranted = PR_TRUE;
 
452
      return rv;
 
453
    }
 
454
    nsCAutoString fqdn;
 
455
    rv = nsWSAUtils::GetOfficialHostName(mServiceURI, fqdn);
 
456
    if (NS_FAILED(rv) || fqdn.IsEmpty())
 
457
      return rv;
 
458
    
 
459
    PRBool isPublic = PR_FALSE;
 
460
    rv = IsPublicService(fqdn.get(), &isPublic);
 
461
    if (NS_SUCCEEDED(rv)) {
 
462
      if (isPublic) {
 
463
        aEntry->mFlags |= SERVICE_LISTED_PUBLIC;
 
464
        *aAccessGranted = PR_TRUE;
 
465
      }
 
466
      aEntry->mFlags |= HAS_MASTER_SERVICE_DECISION; 
 
467
    }
 
468
    return rv;
 
469
  }
 
470
 
 
471
  if (aEntry->mFlags & WSA_GRANT_ACCESS_TO_ALL) {
 
472
    *aAccessGranted = PR_TRUE;
 
473
    return NS_OK;
 
474
  }
 
475
 
 
476
  nsCOMPtr<nsIURI> codebase_uri;
 
477
  rv = GetCodebaseURI(getter_AddRefs(codebase_uri));
 
478
  NS_ENSURE_SUCCESS(rv, rv);
 
479
 
 
480
  nsXPIDLCString tmp;
 
481
  codebase_uri->GetSpec(tmp);
 
482
  const nsAString& codebase = NS_ConvertUTF8toUCS2(tmp);
 
483
 
 
484
  PRUint32 count = aEntry->mInfoArray.Count();
 
485
  PRUint32 index;
 
486
  for (index = 0; index < count; index++) {
 
487
    AccessInfo* access_info = 
 
488
      NS_REINTERPRET_CAST(AccessInfo*, aEntry->mInfoArray.ElementAt(index));
 
489
    NS_ASSERTION(access_info, "Entry is missing attribute information");
 
490
    
 
491
    if (!access_info->mType || kAny.Equals(access_info->mType) || 
 
492
        aRequestType.Equals(access_info->mType)) {
 
493
      if (!access_info->mFrom) {
 
494
        // If "from" is not specified, then all scripts will be  allowed 
 
495
        *aAccessGranted = PR_TRUE;
 
496
        break;
 
497
      }
 
498
      else {
 
499
        if (nsWSAUtils::IsEqual(nsDependentString(access_info->mFrom), 
 
500
                                codebase)) {
 
501
          *aAccessGranted = PR_TRUE;
 
502
          break;
 
503
        }
 
504
      }
 
505
    }
 
506
  }
 
507
 
 
508
  return NS_OK;
 
509
}
 
510
 
 
511
/** 
 
512
  * Validation is based on the following syntax:
 
513
  * 
 
514
  * <!ELEMENT webScriptAccess (delegate?|allow*)>
 
515
  * <!ELEMENT delegate EMPTY>
 
516
  * <!ELEMENT allow EMPTY>
 
517
  * <!ATTLIST allow type|from CDATA #IMPLIED>.
 
518
  *
 
519
  */
 
520
nsresult
 
521
nsWebScriptsAccess::ValidateDocument(nsIDOMDocument* aDocument,
 
522
                                     PRBool* aIsValid)
 
523
{
 
524
  NS_ENSURE_ARG_POINTER(aDocument);
 
525
 
 
526
  *aIsValid = PR_FALSE;
 
527
  nsCOMPtr<nsIDOMElement> rootElement;
 
528
  aDocument->GetDocumentElement(getter_AddRefs(rootElement));
 
529
  
 
530
  nsAutoString ns;
 
531
  nsAutoString name;
 
532
  nsresult rv = rootElement->GetNamespaceURI(ns);
 
533
  if (NS_FAILED(rv))
 
534
    return rv;
 
535
  rootElement->GetLocalName(name);
 
536
  if (NS_FAILED(rv))
 
537
    return rv;
 
538
  
 
539
  if (!ns.Equals(kNamespace2002)) {
 
540
    const PRUnichar *inputs[1]  = { ns.get() };
 
541
    return nsWSAUtils::ReportError(
 
542
                         NS_LITERAL_STRING("UnsupportedNamespace").get(), 
 
543
                         inputs, 1);
 
544
  }
 
545
  if (!name.Equals(kWebScriptAccessTag)) {
 
546
    const PRUnichar *inputs[1]  = { name.get() };
 
547
    return nsWSAUtils::ReportError(
 
548
                         NS_LITERAL_STRING("UnknownRootElement").get(), 
 
549
                         inputs, 1);
 
550
  }
 
551
 
 
552
  nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootElement));
 
553
  NS_ENSURE_TRUE(rootNode, NS_ERROR_UNEXPECTED);
 
554
 
 
555
  nsCOMPtr<nsIDOMNodeList> children;
 
556
  rootNode->GetChildNodes(getter_AddRefs(children));
 
557
  NS_ENSURE_TRUE(children, NS_ERROR_UNEXPECTED);
 
558
 
 
559
  PRUint32 length;
 
560
  children->GetLength(&length);
 
561
 
 
562
  PRBool hadDelegate = PR_FALSE;
 
563
  nsCOMPtr<nsIDOMNode> child, attr;
 
564
  nsCOMPtr<nsIDOMNamedNodeMap> attrs;
 
565
  PRUint32 i;
 
566
  for (i = 0; i < length; i++) {
 
567
    children->Item(i, getter_AddRefs(child));
 
568
    NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
 
569
  
 
570
    PRUint16 type;
 
571
    child->GetNodeType(&type);
 
572
 
 
573
    if (nsIDOMNode::ELEMENT_NODE == type) {
 
574
      rv = child->GetNamespaceURI(ns);
 
575
      if (NS_FAILED(rv))
 
576
        return rv;
 
577
      rv = child->GetLocalName(name);
 
578
      if (NS_FAILED(rv))
 
579
        return rv;
 
580
 
 
581
      if (!ns.Equals(kNamespace2002))
 
582
        continue; // ignore elements with different ns.
 
583
 
 
584
      PRBool hasChildNodes = PR_FALSE;
 
585
      if (name.Equals(kDelegateTag)) {
 
586
        // There can me no more than one delegate element.
 
587
        if (hadDelegate) {
 
588
          const PRUnichar *inputs[1] = { name.get() };
 
589
          return nsWSAUtils::ReportError(
 
590
                               NS_LITERAL_STRING("TooManyElements").get(), 
 
591
                               inputs, 1);
 
592
        }
 
593
        // Make sure that the delegate element is EMPTY.
 
594
        child->HasChildNodes(&hasChildNodes);
 
595
        if (hasChildNodes) {
 
596
          const PRUnichar *inputs[1] = { name.get() };
 
597
          return nsWSAUtils::ReportError(
 
598
                               NS_LITERAL_STRING("ElementNotEmpty").get(), 
 
599
                               inputs, 1);
 
600
        }
 
601
        hadDelegate = PR_TRUE;
 
602
      }
 
603
      else if (name.Equals(kAllowTag)) {
 
604
        // Make sure that the allow element is EMPTY.
 
605
        child->HasChildNodes(&hasChildNodes);
 
606
        if (hasChildNodes) {
 
607
          const PRUnichar *inputs[1] = { name.get() };
 
608
          return nsWSAUtils::ReportError(
 
609
                               NS_LITERAL_STRING("ElementNotEmpty").get(), 
 
610
                               inputs, 1);
 
611
        }
 
612
        rv = child->GetAttributes(getter_AddRefs(attrs));
 
613
        if (NS_FAILED(rv))
 
614
          return rv;
 
615
        
 
616
        PRUint32 count, i;
 
617
        attrs->GetLength(&count);
 
618
        for (i = 0; i < count; i++) {
 
619
          attrs->Item(i, getter_AddRefs(attr));
 
620
          if (attr) {
 
621
            rv = attr->GetLocalName(name);
 
622
            if (NS_FAILED(rv))
 
623
              return rv;
 
624
            if (!name.Equals(kTypeAttr) && !name.Equals(kFromAttr)) {
 
625
              const PRUnichar *inputs[1] = { name.get() };
 
626
              return nsWSAUtils::ReportError(
 
627
                                   NS_LITERAL_STRING("UnknownAttribute").get(), 
 
628
                                   inputs, 1);
 
629
            }
 
630
          }
 
631
        }
 
632
      }
 
633
      else {
 
634
        const PRUnichar *inputs[1] = { name.get() };
 
635
        return nsWSAUtils::ReportError(
 
636
                             NS_LITERAL_STRING("UnknownElement").get(), 
 
637
                             inputs, 1);
 
638
      }
 
639
 
 
640
    }
 
641
  }
 
642
  *aIsValid = PR_TRUE;
 
643
  return NS_OK;
 
644
}
 
645
 
 
646
static PRBool
 
647
IsCharInSet(const char* aSet,
 
648
            const PRUnichar aChar)
 
649
{
 
650
  PRUnichar ch;
 
651
  while ((ch = *aSet)) {
 
652
    if (aChar == PRUnichar(ch)) {
 
653
      return PR_TRUE;
 
654
    }
 
655
    ++aSet;
 
656
  }
 
657
  return PR_FALSE;
 
658
}
 
659
 
 
660
nsresult
 
661
nsWebScriptsAccess::IsPublicService(const char* aHost, PRBool* aReturn)
 
662
{
 
663
  *aReturn = PR_FALSE;
 
664
  nsresult rv = NS_OK;
 
665
  // Cache the master services included in the prefs.
 
666
  if (mMasterServices.Count() == 0) {
 
667
    nsCOMPtr<nsIPrefBranch> prefBranch = 
 
668
      do_GetService(NS_PREFSERVICE_CONTRACTID);
 
669
  
 
670
    if (!prefBranch)
 
671
      return rv;
 
672
 
 
673
    nsXPIDLCString value;
 
674
    rv = prefBranch->GetCharPref("xml.webservice.security.masterservices",
 
675
                                 getter_Copies(value));
 
676
    
 
677
    if (NS_FAILED(rv) || value.IsEmpty())
 
678
      return NS_OK;
 
679
      
 
680
    nsACString::const_iterator begin, end, curr;
 
681
    nsACString::const_iterator uri_begin, uri_end;
 
682
    value.BeginReading(begin);
 
683
    value.EndReading(end);
 
684
    
 
685
    // Parse the comma separated pref. value
 
686
    static const char* kWhitespace = " \n\r\t\b";
 
687
    while (begin != end) {
 
688
      curr = begin;
 
689
      // strip leading whitespaces
 
690
      while (IsCharInSet(kWhitespace, *curr) && ++curr != end);
 
691
      uri_begin = curr;
 
692
      // consume until the delimiter ( comma ).
 
693
      while (curr != end && *curr != ',')
 
694
        ++curr;
 
695
      uri_end = curr;
 
696
      // strip trailing whitespaces
 
697
      while (uri_end != uri_begin) {
 
698
        if (!IsCharInSet(kWhitespace, *(--uri_end))) {
 
699
          ++uri_end; // include the last non whitespace char.
 
700
          break;
 
701
        }
 
702
      }
 
703
      const nsAFlatString& transportURI =
 
704
        NS_ConvertUTF8toUCS2(Substring(uri_begin, uri_end));
 
705
      if (!transportURI.IsEmpty())
 
706
        mMasterServices.AppendString(transportURI);
 
707
      begin = (*curr == ',' && curr != end) ? ++curr : curr;
 
708
    }
 
709
  }
 
710
 
 
711
  // Do nothing if the pref value turns out to be 
 
712
  // strings with nothing but whitespaces.
 
713
  if (mMasterServices.Count() == 0)
 
714
    return rv;
 
715
 
 
716
  // Allocate param block.
 
717
  nsISOAPParameter** bodyBlocks = 
 
718
    NS_STATIC_CAST(nsISOAPParameter**,
 
719
                  nsMemory::Alloc(1 * sizeof(nsISOAPParameter*)));
 
720
  if (!bodyBlocks)
 
721
    return NS_ERROR_OUT_OF_MEMORY;
 
722
 
 
723
  rv = 
 
724
    CallCreateInstance(NS_SOAPPARAMETER_CONTRACTID, &bodyBlocks[0]);
 
725
  
 
726
  if (NS_FAILED(rv)) {
 
727
    NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(0, bodyBlocks);
 
728
    return rv;
 
729
  }
 
730
 
 
731
  nsCOMPtr<nsISOAPBlock> block = do_QueryInterface(bodyBlocks[0], &rv);
 
732
 
 
733
  if (NS_FAILED(rv))
 
734
    return rv;
 
735
 
 
736
  block->SetName(NS_LITERAL_STRING("fqdn"));
 
737
 
 
738
  nsCOMPtr <nsIWritableVariant> variant =
 
739
    do_CreateInstance(NS_VARIANT_CONTRACTID, &rv);
 
740
 
 
741
  if (NS_FAILED(rv))
 
742
    return rv;
 
743
 
 
744
  variant->SetAsString(aHost);
 
745
 
 
746
  block->SetValue(variant);
 
747
 
 
748
    // Create the call instance
 
749
  nsCOMPtr<nsISOAPCall> call = 
 
750
    do_CreateInstance(NS_SOAPCALL_CONTRACTID, &rv);
 
751
  
 
752
  if (NS_FAILED(rv))
 
753
    return rv;
 
754
 
 
755
  nsCOMPtr<nsISOAPEncoding> encoding =
 
756
    do_CreateInstance(NS_SOAPENCODING_CONTRACTID, &rv);
 
757
  
 
758
  if (NS_FAILED(rv))
 
759
    return rv;
 
760
 
 
761
  call->SetEncoding(encoding);
 
762
  
 
763
  // Since the SOAP request to the central server will be made
 
764
  // from the native code we can safely override cross-domain 
 
765
  // checks by pushing in a null jscontext on the context stack.
 
766
  nsCOMPtr<nsIJSContextStack> stack = 
 
767
    do_GetService("@mozilla.org/js/xpc/ContextStack;1");
 
768
  if (stack)
 
769
    stack->Push(nsnull);
 
770
 
 
771
  nsCOMPtr<nsISOAPResponse> response;
 
772
  PRInt32 i, count = mMasterServices.Count();
 
773
  for (i = 0; i < count && !response; i++) {
 
774
    rv = 
 
775
      call->SetTransportURI(*mMasterServices.StringAt(i));
 
776
    
 
777
    if (NS_FAILED(rv))
 
778
      break;
 
779
    
 
780
    rv = call->Encode(nsISOAPMessage::VERSION_1_1,
 
781
                      kIsServicePublic, 
 
782
                      kNamespace2002, // The target URI
 
783
                      0, 0, 1, bodyBlocks);
 
784
    if (NS_FAILED(rv))
 
785
      break;
 
786
  
 
787
    call->Invoke(getter_AddRefs(response)); // XXX - How to handle time out and 404?
 
788
  }
 
789
  
 
790
  if (stack) {
 
791
    JSContext* cx;
 
792
    stack->Pop(&cx);
 
793
    NS_ASSERTION(!cx, "context should be null");
 
794
  }
 
795
 
 
796
  if (!response)
 
797
    return rv;
 
798
  
 
799
  nsCOMPtr<nsISOAPFault> fault;
 
800
  response->GetFault(getter_AddRefs(fault));
 
801
    
 
802
  if (fault) {
 
803
    nsAutoString faultNamespaceURI, faultCode, faultString;
 
804
    fault->GetFaultNamespaceURI(faultNamespaceURI);
 
805
    fault->GetFaultCode(faultCode);
 
806
    fault->GetFaultString(faultString);
 
807
    const PRUnichar *inputs[5]  = 
 
808
      { 
 
809
        kNamespace2002.get(),
 
810
        kIsServicePublic.get(),
 
811
        faultNamespaceURI.get(),
 
812
        faultCode.get(),
 
813
        faultString.get()
 
814
      };
 
815
    return nsWSAUtils::ReportError(
 
816
                        NS_LITERAL_STRING("SOAPFault").get(), 
 
817
                        inputs, 5);
 
818
  }
 
819
  else {
 
820
    PRUint32 bodyCount;
 
821
    rv = response->GetParameters(PR_FALSE, &bodyCount, &bodyBlocks);
 
822
    NS_ASSERTION(bodyBlocks, "insufficient information");
 
823
 
 
824
    if (!bodyBlocks || NS_FAILED(rv))
 
825
      return rv;
 
826
    
 
827
    NS_ASSERTION(bodyCount == 1, "body seems to contain unnecessary information.");
 
828
    block = do_QueryInterface(bodyBlocks[0], &rv);
 
829
    
 
830
    if (NS_FAILED(rv))
 
831
      return rv;
 
832
    
 
833
    nsCOMPtr<nsIVariant> value;
 
834
    rv = block->GetValue(getter_AddRefs(value));
 
835
    
 
836
    if (NS_FAILED(rv) || !value)
 
837
      return rv;
 
838
    
 
839
    rv = value->GetAsBool(aReturn);
 
840
  }
 
841
 
 
842
  return rv;
 
843
}
 
844