Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
* License, v. 2.0. If a copy of the MPL was not distributed with this
4
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "nsISupports.idl"
7
interface nsIURI;
8
interface nsIObjectInputStream;
9
interface nsIURIMutator;
10
11
%{C++
12
#include "nsString.h"
13
#include "nsCOMPtr.h"
14
#include <functional>
15
16
#undef SetPort // XXX Windows!
17
18
namespace mozilla {
19
class Encoding;
20
}
21
22
namespace mozilla {
23
namespace ipc {
24
class URIParams;
25
} // namespace ipc
26
} // namespace mozilla
27
28
template <class T>
29
class BaseURIMutator
30
{
31
// This is the base class that can be extended by implementors of nsIURIMutator
32
// in order to avoid code duplication
33
// Class type T should be the type of the class that implements nsIURI
34
protected:
35
virtual T* Create()
36
{
37
return new T();
38
}
39
40
MOZ_MUST_USE nsresult InitFromURI(T* aURI)
41
{
42
nsCOMPtr<nsIURI> clone;
43
nsresult rv = aURI->Clone(getter_AddRefs(clone));
44
if (NS_FAILED(rv)) {
45
return rv;
46
}
47
mURI = static_cast<T*>(clone.get());
48
return NS_OK;
49
}
50
51
MOZ_MUST_USE nsresult InitFromInputStream(nsIObjectInputStream* aStream)
52
{
53
RefPtr<T> uri = Create();
54
nsresult rv = uri->ReadPrivate(aStream);
55
if (NS_FAILED(rv)) {
56
return rv;
57
}
58
mURI = uri.forget();
59
return NS_OK;
60
}
61
62
MOZ_MUST_USE nsresult InitFromIPCParams(const mozilla::ipc::URIParams& aParams)
63
{
64
RefPtr<T> uri = Create();
65
bool ret = uri->Deserialize(aParams);
66
if (!ret) {
67
return NS_ERROR_FAILURE;
68
}
69
mURI = uri.forget();
70
return NS_OK;
71
}
72
73
MOZ_MUST_USE nsresult InitFromSpec(const nsACString& aSpec)
74
{
75
nsresult rv = NS_OK;
76
RefPtr<T> uri;
77
if (mURI) {
78
// This only works because all other Init methods create a new object
79
mURI.swap(uri);
80
} else {
81
uri = Create();
82
}
83
84
rv = uri->SetSpecInternal(aSpec);
85
if (NS_FAILED(rv)) {
86
return rv;
87
}
88
mURI = uri.forget();
89
return NS_OK;
90
}
91
92
RefPtr<T> mURI;
93
};
94
95
// Since most implementations of nsIURIMutator would extend BaseURIMutator,
96
// some methods would have the same implementation. We provide a useful macro
97
// to avoid code duplication.
98
#define NS_DEFINE_NSIMUTATOR_COMMON \
99
MOZ_MUST_USE NS_IMETHOD \
100
Deserialize(const mozilla::ipc::URIParams& aParams) override \
101
{ \
102
return InitFromIPCParams(aParams); \
103
} \
104
\
105
MOZ_MUST_USE NS_IMETHOD \
106
Finalize(nsIURI** aURI) override \
107
{ \
108
mURI.forget(aURI); return NS_OK; \
109
} \
110
\
111
MOZ_MUST_USE NS_IMETHOD \
112
SetSpec(const nsACString& aSpec, nsIURIMutator** aMutator) override \
113
{ \
114
if (aMutator) NS_ADDREF(*aMutator = this); \
115
return InitFromSpec(aSpec); \
116
} \
117
118
// Implements AddRef, Release and QueryInterface for the mutator
119
#define NS_IMPL_NSIURIMUTATOR_ISUPPORTS(aClass, ...) \
120
NS_IMPL_ADDREF(aClass) \
121
NS_IMPL_RELEASE(aClass) \
122
NS_IMPL_NSIURIMUTATOR_QUERY_INTERFACE(aClass, __VA_ARGS__) \
123
124
// The list of interfaces is queried and an AddRef-ed pointer is returned if
125
// there is a match. Otherwise, we call QueryInterface on mURI and return.
126
// The reason for this specialized QueryInterface implementation is that we
127
// we want to be able to instantiate the mutator for a given CID of a
128
// nsIURI implementation, call nsISerializable.Read() on the mutator to
129
// deserialize the URI then QueryInterface the mutator to an nsIURI interface.
130
// See bug 1442239.
131
// If you QueryInterface a mutator to an interface of the URI
132
// implementation this is similar to calling Finalize.
133
#define NS_IMPL_NSIURIMUTATOR_QUERY_INTERFACE(aClass, ...) \
134
static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0, \
135
"Need more arguments"); \
136
NS_INTERFACE_MAP_BEGIN(aClass) \
137
nsCOMPtr<nsIURI> uri; \
138
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIURIMutator) \
139
MOZ_FOR_EACH(NS_INTERFACE_MAP_ENTRY, (), (__VA_ARGS__)) \
140
if (aIID.Equals(NS_GET_IID(nsIClassInfo))) { \
141
foundInterface = nullptr; \
142
} else \
143
if (mURI && \
144
NS_SUCCEEDED(mURI->QueryInterface(aIID, getter_AddRefs(uri)))) { \
145
mURI = nullptr; \
146
foundInterface = uri.get(); \
147
} else \
148
NS_INTERFACE_MAP_END \
149
150
%}
151
152
[ptr] native Encoding(const mozilla::Encoding);
153
[ref] native const_URIParams_ref(const mozilla::ipc::URIParams);
154
155
[scriptable, builtinclass, uuid(1fc53257-898b-4c5e-b69c-05bc84b4cd8f)]
156
interface nsIURISetSpec : nsISupports
157
{
158
/**
159
* This setter is different from all other setters because it may be used to
160
* initialize the object. We define it separately allowing mutator implementors
161
* to define it separately, while the rest of the setters may be simply
162
* forwarded to the mutable URI.
163
*/
164
[must_use] nsIURIMutator setSpec(in AUTF8String aSpec);
165
};
166
167
/**
168
* These methods allow the mutator to change various parts of the URI.
169
* They return the same nsIURIMutator so that we may chain setter operations:
170
* Example:
171
* let newURI = uri.mutate()
172
* .setSpec("http://example.com")
173
* .setQuery("hello")
174
* .finalize();
175
*/
176
[scriptable, builtinclass, uuid(5403a6ec-99d7-405e-8b45-9f805bbdfcef)]
177
interface nsIURISetters : nsIURISetSpec
178
{
179
/**
180
* Setting the scheme outside of a protocol handler implementation is highly
181
* discouraged since that will generally lead to incorrect results.
182
*/
183
[must_use] nsIURIMutator setScheme(in AUTF8String aScheme);
184
[must_use] nsIURIMutator setUserPass(in AUTF8String aUserPass);
185
[must_use] nsIURIMutator setUsername(in AUTF8String aUsername);
186
[must_use] nsIURIMutator setPassword(in AUTF8String aPassword);
187
188
/**
189
* If you setHostPort to a value that only has a host part, the port
190
* will not be reset. To reset the port set it to -1 beforehand.
191
* If setting the host succeeds, this method will return NS_OK, even if
192
* setting the port fails (error in parsing the port, or value out of range)
193
*/
194
[must_use] nsIURIMutator setHostPort(in AUTF8String aHostPort);
195
[must_use] nsIURIMutator setHost(in AUTF8String aHost);
196
[must_use] nsIURIMutator setPort(in long aPort);
197
[must_use] nsIURIMutator setPathQueryRef(in AUTF8String aPathQueryRef);
198
[must_use] nsIURIMutator setRef(in AUTF8String aRef);
199
[must_use] nsIURIMutator setFilePath(in AUTF8String aFilePath);
200
[must_use] nsIURIMutator setQuery(in AUTF8String aQuery);
201
[must_use, noscript] nsIURIMutator setQueryWithEncoding(in AUTF8String query, in Encoding encoding);
202
};
203
204
%{C++
205
206
// Using this macro instead of NS_FORWARD_SAFE_NSIURISETTERS makes chaining
207
// setter operations possible.
208
#define NS_FORWARD_SAFE_NSIURISETTERS_RET(_to) \
209
MOZ_MUST_USE NS_IMETHOD \
210
SetScheme(const nsACString& aScheme, nsIURIMutator** aMutator) override \
211
{ \
212
if (aMutator) NS_ADDREF(*aMutator = this); \
213
return !_to ? NS_ERROR_NULL_POINTER : _to->SetScheme(aScheme); \
214
} \
215
MOZ_MUST_USE NS_IMETHOD \
216
SetUserPass(const nsACString& aUserPass, nsIURIMutator** aMutator) override \
217
{ \
218
if (aMutator) NS_ADDREF(*aMutator = this); \
219
return !_to ? NS_ERROR_NULL_POINTER : _to->SetUserPass(aUserPass); \
220
} \
221
MOZ_MUST_USE NS_IMETHOD \
222
SetUsername(const nsACString& aUsername, nsIURIMutator** aMutator) override \
223
{ \
224
if (aMutator) NS_ADDREF(*aMutator = this); \
225
return !_to ? NS_ERROR_NULL_POINTER : _to->SetUsername(aUsername); \
226
} \
227
MOZ_MUST_USE NS_IMETHOD \
228
SetPassword(const nsACString& aPassword, nsIURIMutator** aMutator) override \
229
{ \
230
if (aMutator) NS_ADDREF(*aMutator = this); \
231
return !_to ? NS_ERROR_NULL_POINTER : _to->SetPassword(aPassword); \
232
} \
233
MOZ_MUST_USE NS_IMETHOD \
234
SetHostPort(const nsACString& aHostPort, nsIURIMutator** aMutator) override \
235
{ \
236
if (aMutator) NS_ADDREF(*aMutator = this); \
237
return !_to ? NS_ERROR_NULL_POINTER : _to->SetHostPort(aHostPort); \
238
} \
239
MOZ_MUST_USE NS_IMETHOD \
240
SetHost(const nsACString& aHost, nsIURIMutator** aMutator) override \
241
{ \
242
if (aMutator) NS_ADDREF(*aMutator = this); \
243
return !_to ? NS_ERROR_NULL_POINTER : _to->SetHost(aHost); \
244
} \
245
MOZ_MUST_USE NS_IMETHOD \
246
SetPort(int32_t aPort, nsIURIMutator** aMutator) override \
247
{ \
248
if (aMutator) NS_ADDREF(*aMutator = this); \
249
return !_to ? NS_ERROR_NULL_POINTER : _to->SetPort(aPort); \
250
} \
251
MOZ_MUST_USE NS_IMETHOD \
252
SetPathQueryRef(const nsACString& aPathQueryRef, nsIURIMutator** aMutator) override \
253
{ \
254
if (aMutator) NS_ADDREF(*aMutator = this); \
255
return !_to ? NS_ERROR_NULL_POINTER : _to->SetPathQueryRef(aPathQueryRef); \
256
} \
257
MOZ_MUST_USE NS_IMETHOD \
258
SetRef(const nsACString& aRef, nsIURIMutator** aMutator) override \
259
{ \
260
if (aMutator) NS_ADDREF(*aMutator = this); \
261
return !_to ? NS_ERROR_NULL_POINTER : _to->SetRef(aRef); \
262
} \
263
MOZ_MUST_USE NS_IMETHOD \
264
SetFilePath(const nsACString& aFilePath, nsIURIMutator** aMutator) override \
265
{ \
266
if (aMutator) NS_ADDREF(*aMutator = this); \
267
return !_to ? NS_ERROR_NULL_POINTER : _to->SetFilePath(aFilePath); \
268
} \
269
MOZ_MUST_USE NS_IMETHOD \
270
SetQuery(const nsACString& aQuery, nsIURIMutator** aMutator) override \
271
{ \
272
if (aMutator) NS_ADDREF(*aMutator = this); \
273
return !_to ? NS_ERROR_NULL_POINTER : _to->SetQuery(aQuery); \
274
} \
275
MOZ_MUST_USE NS_IMETHOD \
276
SetQueryWithEncoding(const nsACString& query, const mozilla::Encoding *encoding, nsIURIMutator** aMutator) override \
277
{ \
278
if (aMutator) NS_ADDREF(*aMutator = this); \
279
return !_to ? NS_ERROR_NULL_POINTER : _to->SetQueryWithEncoding(query, encoding); \
280
} \
281
282
%}
283
284
[scriptable, builtinclass, uuid(4d1f3103-1c44-4dcd-b717-5d22a697a7d9)]
285
interface nsIURIMutator : nsIURISetters
286
{
287
/**
288
* Initalizes the URI by reading IPC URIParams.
289
* See nsIURI.
290
*/
291
[noscript, notxpcom, must_use]
292
nsresult deserialize(in const_URIParams_ref aParams);
293
294
/**
295
* Finishes changing or constructing the URI and returns an immutable URI.
296
*/
297
[must_use]
298
nsIURI finalize();
299
};
300
301
%{C++
302
303
// This templated struct is used to extract the class type of the method
304
// passed to NS_MutatorMethod.
305
template <typename Method>
306
struct nsMethodTypeTraits;
307
308
template <class C, typename R, typename... As>
309
struct nsMethodTypeTraits<R(C::*)(As...)>
310
{
311
typedef C class_type;
312
};
313
314
#ifdef NS_HAVE_STDCALL
315
template <class C, typename R, typename... As>
316
struct nsMethodTypeTraits<R(__stdcall C::*)(As...)>
317
{
318
typedef C class_type;
319
};
320
#endif
321
322
// This helper returns a std::function that will be applied on the
323
// nsIURIMutator. The type of `Interface` will be deduced from the method type.
324
// aMethod will be called on the target object if it successfully QIs to
325
// `Interface`, and the arguments will be passed to the call.
326
template <typename Method, typename... Args>
327
const std::function<nsresult(nsIURIMutator*)>
328
NS_MutatorMethod(Method aMethod, Args ...aArgs)
329
{
330
// Capture arguments by value, otherwise we crash.
331
return [=](nsIURIMutator* aMutator) {
332
typedef typename nsMethodTypeTraits<Method>::class_type Interface;
333
nsresult rv;
334
nsCOMPtr<Interface> target = do_QueryInterface(aMutator, &rv);
335
NS_ENSURE_SUCCESS(rv, rv);
336
rv = (target->*aMethod)(aArgs...);
337
if (NS_FAILED(rv)) return rv;
338
return NS_OK;
339
};
340
}
341
342
// This class provides a useful helper that allows chaining of setter operations
343
class MOZ_STACK_CLASS NS_MutateURI
344
{
345
public:
346
explicit NS_MutateURI(nsIURI* aURI);
347
explicit NS_MutateURI(const char * aContractID);
348
349
explicit NS_MutateURI(nsIURIMutator* m)
350
{
351
mStatus = m ? NS_OK : NS_ERROR_NULL_POINTER;
352
mMutator = m;
353
NS_ENSURE_SUCCESS_VOID(mStatus);
354
}
355
356
NS_MutateURI& SetSpec(const nsACString& aSpec)
357
{
358
if (NS_FAILED(mStatus)) {
359
return *this;
360
}
361
mStatus = mMutator->SetSpec(aSpec, nullptr);
362
return *this;
363
}
364
NS_MutateURI& SetScheme(const nsACString& aScheme)
365
{
366
if (NS_FAILED(mStatus)) {
367
return *this;
368
}
369
mStatus = mMutator->SetScheme(aScheme, nullptr);
370
NS_ENSURE_SUCCESS(mStatus, *this);
371
return *this;
372
}
373
NS_MutateURI& SetUserPass(const nsACString& aUserPass)
374
{
375
if (NS_FAILED(mStatus)) {
376
return *this;
377
}
378
mStatus = mMutator->SetUserPass(aUserPass, nullptr);
379
NS_ENSURE_SUCCESS(mStatus, *this);
380
return *this;
381
}
382
NS_MutateURI& SetUsername(const nsACString& aUsername)
383
{
384
if (NS_FAILED(mStatus)) {
385
return *this;
386
}
387
mStatus = mMutator->SetUsername(aUsername, nullptr);
388
NS_ENSURE_SUCCESS(mStatus, *this);
389
return *this;
390
}
391
NS_MutateURI& SetPassword(const nsACString& aPassword)
392
{
393
if (NS_FAILED(mStatus)) {
394
return *this;
395
}
396
mStatus = mMutator->SetPassword(aPassword, nullptr);
397
NS_ENSURE_SUCCESS(mStatus, *this);
398
return *this;
399
}
400
NS_MutateURI& SetHostPort(const nsACString& aHostPort)
401
{
402
if (NS_FAILED(mStatus)) {
403
return *this;
404
}
405
mStatus = mMutator->SetHostPort(aHostPort, nullptr);
406
NS_ENSURE_SUCCESS(mStatus, *this);
407
return *this;
408
}
409
NS_MutateURI& SetHost(const nsACString& aHost)
410
{
411
if (NS_FAILED(mStatus)) {
412
return *this;
413
}
414
mStatus = mMutator->SetHost(aHost, nullptr);
415
NS_ENSURE_SUCCESS(mStatus, *this);
416
return *this;
417
}
418
NS_MutateURI& SetPort(int32_t aPort)
419
{
420
if (NS_FAILED(mStatus)) {
421
return *this;
422
}
423
mStatus = mMutator->SetPort(aPort, nullptr);
424
NS_ENSURE_SUCCESS(mStatus, *this);
425
return *this;
426
}
427
NS_MutateURI& SetPathQueryRef(const nsACString& aPathQueryRef)
428
{
429
if (NS_FAILED(mStatus)) {
430
return *this;
431
}
432
mStatus = mMutator->SetPathQueryRef(aPathQueryRef, nullptr);
433
NS_ENSURE_SUCCESS(mStatus, *this);
434
return *this;
435
}
436
NS_MutateURI& SetRef(const nsACString& aRef)
437
{
438
if (NS_FAILED(mStatus)) {
439
return *this;
440
}
441
mStatus = mMutator->SetRef(aRef, nullptr);
442
NS_ENSURE_SUCCESS(mStatus, *this);
443
return *this;
444
}
445
NS_MutateURI& SetFilePath(const nsACString& aFilePath)
446
{
447
if (NS_FAILED(mStatus)) {
448
return *this;
449
}
450
mStatus = mMutator->SetFilePath(aFilePath, nullptr);
451
NS_ENSURE_SUCCESS(mStatus, *this);
452
return *this;
453
}
454
NS_MutateURI& SetQuery(const nsACString& aQuery)
455
{
456
if (NS_FAILED(mStatus)) {
457
return *this;
458
}
459
mStatus = mMutator->SetQuery(aQuery, nullptr);
460
NS_ENSURE_SUCCESS(mStatus, *this);
461
return *this;
462
}
463
NS_MutateURI& SetQueryWithEncoding(const nsACString& query, const mozilla::Encoding *encoding)
464
{
465
if (NS_FAILED(mStatus)) {
466
return *this;
467
}
468
mStatus = mMutator->SetQueryWithEncoding(query, encoding, nullptr);
469
NS_ENSURE_SUCCESS(mStatus, *this);
470
return *this;
471
}
472
473
/**
474
* This method allows consumers to call the methods declared in other
475
* interfaces implemented by the mutator object.
476
*
477
* Example:
478
* nsCOMPtr<nsIURI> uri;
479
* nsresult rv = NS_MutateURI(new URIClass::Mutator())
480
* .SetSpec(aSpec)
481
* .Apply(NS_MutatorMethod(&SomeInterface::Method, arg1, arg2))
482
* .Finalize(uri);
483
*
484
* If mMutator does not implement SomeInterface, do_QueryInterface will fail
485
* and the method will not be called.
486
* If aMethod does not exist, or if there is a mismatch between argument
487
* types, or the number of arguments, then there will be a compile error.
488
*/
489
NS_MutateURI& Apply(const std::function<nsresult(nsIURIMutator*)>& aFunction)
490
{
491
if (NS_FAILED(mStatus)) {
492
return *this;
493
}
494
mStatus = aFunction(mMutator);
495
return *this;
496
}
497
498
template <class C>
499
MOZ_MUST_USE nsresult Finalize(nsCOMPtr<C>& aURI)
500
{
501
NS_ENSURE_SUCCESS(mStatus, mStatus);
502
503
nsCOMPtr<nsIURI> uri;
504
mStatus = mMutator->Finalize(getter_AddRefs(uri));
505
NS_ENSURE_SUCCESS(mStatus, mStatus);
506
507
aURI = do_QueryInterface(uri, &mStatus);
508
NS_ENSURE_SUCCESS(mStatus, mStatus);
509
510
mStatus = NS_ERROR_NOT_AVAILABLE; // Second call to Finalize should fail.
511
return NS_OK;
512
}
513
514
// Overload for nsIURI to avoid query interface.
515
MOZ_MUST_USE nsresult Finalize(nsCOMPtr<nsIURI>& aURI)
516
{
517
if (NS_FAILED(mStatus)) return mStatus;
518
mStatus = mMutator->Finalize(getter_AddRefs(aURI));
519
NS_ENSURE_SUCCESS(mStatus, mStatus);
520
521
mStatus = NS_ERROR_NOT_AVAILABLE; // Second call to Finalize should fail.
522
return NS_OK;
523
}
524
525
template <class C>
526
MOZ_MUST_USE nsresult Finalize(C** aURI)
527
{
528
NS_ENSURE_SUCCESS(mStatus, mStatus);
529
530
nsCOMPtr<nsIURI> uri;
531
mStatus = mMutator->Finalize(getter_AddRefs(uri));
532
NS_ENSURE_SUCCESS(mStatus, mStatus);
533
534
nsCOMPtr<C> result = do_QueryInterface(uri, &mStatus);
535
NS_ENSURE_SUCCESS(mStatus, mStatus);
536
537
result.forget(aURI);
538
mStatus = NS_ERROR_NOT_AVAILABLE; // Second call to Finalize should fail.
539
return NS_OK;
540
}
541
542
MOZ_MUST_USE nsresult Finalize(nsIURI** aURI)
543
{
544
if (NS_FAILED(mStatus)) return mStatus;
545
mStatus = mMutator->Finalize(aURI);
546
NS_ENSURE_SUCCESS(mStatus, mStatus);
547
548
mStatus = NS_ERROR_NOT_AVAILABLE; // Second call to Finalize should fail.
549
return NS_OK;
550
}
551
552
nsresult GetStatus() { return mStatus; }
553
private:
554
nsresult mStatus;
555
nsCOMPtr<nsIURIMutator> mMutator;
556
};
557
558
%}