nsIconURI.cpp (16828B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set sw=2 sts=2 ts=2 et tw=80: 3 * 4 * This Source Code Form is subject to the terms of the Mozilla Public 5 * License, v. 2.0. If a copy of the MPL was not distributed with this 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 7 8 #include "nsIconURI.h" 9 10 #include "mozilla/ipc/URIUtils.h" 11 #include "mozilla/Sprintf.h" 12 13 #include "nsIClassInfoImpl.h" 14 #include "nsIIOService.h" 15 #include "nsISerializable.h" 16 #include "nsIObjectInputStream.h" 17 #include "nsIObjectOutputStream.h" 18 #include "nsIURL.h" 19 #include "nsNetUtil.h" 20 #include "plstr.h" 21 #include "nsCRT.h" 22 #include <stdlib.h> 23 24 using namespace mozilla; 25 using namespace mozilla::ipc; 26 27 #define DEFAULT_IMAGE_SIZE 16 28 29 #if defined(MAX_PATH) 30 # define SANE_FILE_NAME_LEN MAX_PATH 31 #elif defined(PATH_MAX) 32 # define SANE_FILE_NAME_LEN PATH_MAX 33 #else 34 # define SANE_FILE_NAME_LEN 1024 35 #endif 36 37 static NS_DEFINE_CID(kThisIconURIImplementationCID, 38 NS_THIS_ICONURI_IMPLEMENTATION_CID); 39 40 //////////////////////////////////////////////////////////////////////////////// 41 42 NS_IMPL_CLASSINFO(nsMozIconURI, nullptr, nsIClassInfo::THREADSAFE, 43 NS_ICONURI_CID) 44 // Empty CI getter. We only need nsIClassInfo for Serialization 45 NS_IMPL_CI_INTERFACE_GETTER0(nsMozIconURI) 46 47 nsMozIconURI::nsMozIconURI() : mSize(DEFAULT_IMAGE_SIZE) {} 48 49 nsMozIconURI::~nsMozIconURI() = default; 50 51 NS_IMPL_ADDREF(nsMozIconURI) 52 NS_IMPL_RELEASE(nsMozIconURI) 53 54 NS_INTERFACE_MAP_BEGIN(nsMozIconURI) 55 if (aIID.Equals(kThisIconURIImplementationCID)) { 56 foundInterface = static_cast<nsIURI*>(this); 57 } else 58 NS_INTERFACE_MAP_ENTRY(nsIMozIconURI) 59 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIURI) 60 NS_INTERFACE_MAP_ENTRY(nsIURI) 61 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsINestedURI, mIconURL) 62 NS_INTERFACE_MAP_ENTRY(nsISerializable) 63 NS_IMPL_QUERY_CLASSINFO(nsMozIconURI) 64 NS_INTERFACE_MAP_END 65 66 #define MOZICON_SCHEME "moz-icon:" 67 #define MOZICON_SCHEME_LEN (sizeof(MOZICON_SCHEME) - 1) 68 69 //////////////////////////////////////////////////////////////////////////////// 70 // nsIURI methods: 71 72 NS_IMETHODIMP 73 nsMozIconURI::GetSpec(nsACString& aSpec) { 74 aSpec = MOZICON_SCHEME; 75 76 if (mIconURL) { 77 nsAutoCString fileIconSpec; 78 nsresult rv = mIconURL->GetSpec(fileIconSpec); 79 NS_ENSURE_SUCCESS(rv, rv); 80 aSpec += fileIconSpec; 81 } else if (!mStockIcon.IsEmpty()) { 82 aSpec += "//stock/"; 83 aSpec += mStockIcon; 84 } else { 85 aSpec += "//"; 86 aSpec += mFileName; 87 } 88 89 aSpec += "?size="; 90 { 91 char buf[20]; 92 SprintfLiteral(buf, "%d", mSize); 93 aSpec.Append(buf); 94 } 95 96 if (!mContentType.IsEmpty()) { 97 aSpec += "&contentType="; 98 aSpec += mContentType.get(); 99 } 100 101 if (mScale != 1) { 102 aSpec += "&scale="; 103 aSpec.AppendInt(mScale); 104 } 105 106 if (mDark) { 107 aSpec += "&dark="; 108 aSpec.AppendInt(*mDark ? 1 : 0); 109 } 110 111 return NS_OK; 112 } 113 114 NS_IMETHODIMP 115 nsMozIconURI::GetSpecIgnoringRef(nsACString& result) { return GetSpec(result); } 116 117 NS_IMETHODIMP 118 nsMozIconURI::GetDisplaySpec(nsACString& aUnicodeSpec) { 119 return GetSpec(aUnicodeSpec); 120 } 121 122 NS_IMETHODIMP 123 nsMozIconURI::GetDisplayHostPort(nsACString& aUnicodeHostPort) { 124 return GetHostPort(aUnicodeHostPort); 125 } 126 127 NS_IMETHODIMP 128 nsMozIconURI::GetDisplayHost(nsACString& aUnicodeHost) { 129 return GetHost(aUnicodeHost); 130 } 131 132 NS_IMETHODIMP 133 nsMozIconURI::GetDisplayPrePath(nsACString& aPrePath) { 134 return GetPrePath(aPrePath); 135 } 136 137 NS_IMETHODIMP 138 nsMozIconURI::GetHasRef(bool* result) { 139 *result = false; 140 return NS_OK; 141 } 142 143 NS_IMETHODIMP 144 nsMozIconURI::GetHasUserPass(bool* result) { 145 *result = false; 146 return NS_OK; 147 } 148 149 NS_IMETHODIMP 150 nsMozIconURI::GetHasQuery(bool* result) { 151 *result = false; 152 return NS_OK; 153 } 154 155 NS_IMPL_NSIURIMUTATOR_ISUPPORTS(nsMozIconURI::Mutator, nsIURISetters, 156 nsIURIMutator, nsISerializable) 157 158 NS_IMETHODIMP 159 nsMozIconURI::Mutate(nsIURIMutator** aMutator) { 160 RefPtr<nsMozIconURI::Mutator> mutator = new nsMozIconURI::Mutator(); 161 nsresult rv = mutator->InitFromURI(this); 162 if (NS_FAILED(rv)) { 163 return rv; 164 } 165 mutator.forget(aMutator); 166 return NS_OK; 167 } 168 169 // helper function for parsing out attributes like size, and contentType 170 // from the icon url. 171 // takes a string like ?size=32&contentType=text/html and returns a new string 172 // containing just the attribute value. i.e you could pass in this string with 173 // an attribute name of 'size=', this will return 32 174 // Assumption: attribute pairs in the string are separated by '&'. 175 static void extractAttributeValue(const char* aSearchString, 176 const char* aAttributeName, 177 nsCString& aResult) { 178 aResult.Truncate(); 179 180 if (aSearchString && aAttributeName) { 181 // search the string for attributeName 182 uint32_t attributeNameSize = strlen(aAttributeName); 183 const char* startOfAttribute = PL_strcasestr(aSearchString, aAttributeName); 184 if (startOfAttribute && 185 (*(startOfAttribute - 1) == '?' || *(startOfAttribute - 1) == '&')) { 186 startOfAttribute += attributeNameSize; // skip over the attributeName 187 // is there something after the attribute name 188 if (*startOfAttribute) { 189 const char* endofAttribute = strchr(startOfAttribute, '&'); 190 if (endofAttribute) { 191 aResult.Assign(Substring(startOfAttribute, endofAttribute)); 192 } else { 193 aResult.Assign(startOfAttribute); 194 } 195 } // if we have a attribute value 196 } // if we have a attribute name 197 } // if we got non-null search string and attribute name values 198 } 199 200 nsresult nsMozIconURI::SetSpecInternal(const nsACString& aSpec) { 201 // Reset everything to default values. 202 mIconURL = nullptr; 203 mSize = DEFAULT_IMAGE_SIZE; 204 mContentType.Truncate(); 205 mFileName.Truncate(); 206 mStockIcon.Truncate(); 207 mScale = 1; 208 mDark.reset(); 209 210 nsAutoCString iconSpec(aSpec); 211 if (!Substring(iconSpec, 0, MOZICON_SCHEME_LEN) 212 .EqualsLiteral(MOZICON_SCHEME) || 213 (!Substring(iconSpec, MOZICON_SCHEME_LEN, 7).EqualsLiteral("file://") && 214 // Checking for the leading '//' will match both the '//stock/' and 215 // '//.foo' cases: 216 !Substring(iconSpec, MOZICON_SCHEME_LEN, 2).EqualsLiteral("//"))) { 217 return NS_ERROR_MALFORMED_URI; 218 } 219 220 int32_t questionMarkPos = iconSpec.Find("?"); 221 if (questionMarkPos != -1 && 222 static_cast<int32_t>(iconSpec.Length()) > (questionMarkPos + 1)) { 223 extractAttributeValue(iconSpec.get(), "contentType=", mContentType); 224 225 nsAutoCString sizeString; 226 extractAttributeValue(iconSpec.get(), "size=", sizeString); 227 if (!sizeString.IsEmpty()) { 228 int32_t sizeValue = atoi(sizeString.get()); 229 if (sizeValue > 0) { 230 mSize = sizeValue; 231 } 232 } 233 234 nsAutoCString scaleString; 235 extractAttributeValue(iconSpec.get(), "scale=", scaleString); 236 if (!scaleString.IsEmpty()) { 237 int32_t scaleValue = atoi(scaleString.get()); 238 if (scaleValue > 0) { 239 mScale = scaleValue; 240 } 241 } 242 243 nsAutoCString darkString; 244 extractAttributeValue(iconSpec.get(), "dark=", darkString); 245 if (!darkString.IsEmpty()) { 246 int32_t darkValue = atoi(darkString.get()); 247 mDark = Some(darkValue != 0); 248 } 249 } 250 251 int32_t pathLength = iconSpec.Length() - MOZICON_SCHEME_LEN; 252 if (questionMarkPos != -1) { 253 pathLength = questionMarkPos - MOZICON_SCHEME_LEN; 254 } 255 if (pathLength < 3) { 256 return NS_ERROR_MALFORMED_URI; 257 } 258 259 nsAutoCString iconPath(Substring(iconSpec, MOZICON_SCHEME_LEN, pathLength)); 260 261 // Icon URI path can have three forms: 262 // (1) //stock/<icon-identifier> 263 // (2) //<some dummy file with an extension> 264 // (3) a valid URL 265 266 if (!strncmp("//stock/", iconPath.get(), 8)) { 267 mStockIcon.Assign(Substring(iconPath, 8)); 268 // An icon identifier must always be specified. 269 if (mStockIcon.IsEmpty()) { 270 return NS_ERROR_MALFORMED_URI; 271 } 272 return NS_OK; 273 } 274 275 if (StringBeginsWith(iconPath, "//"_ns)) { 276 // Sanity check this supposed dummy file name. 277 if (iconPath.Length() > SANE_FILE_NAME_LEN) { 278 return NS_ERROR_MALFORMED_URI; 279 } 280 iconPath.Cut(0, 2); 281 mFileName.Assign(iconPath); 282 } 283 284 nsresult rv; 285 nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); 286 NS_ENSURE_SUCCESS(rv, rv); 287 288 nsCOMPtr<nsIURI> uri; 289 ioService->NewURI(iconPath, nullptr, nullptr, getter_AddRefs(uri)); 290 mIconURL = do_QueryInterface(uri); 291 if (mIconURL) { 292 // The inner URI should be a 'file:' one. If not, bail. 293 if (!mIconURL->SchemeIs("file")) { 294 return NS_ERROR_MALFORMED_URI; 295 } 296 mFileName.Truncate(); 297 } else if (mFileName.IsEmpty()) { 298 return NS_ERROR_MALFORMED_URI; 299 } 300 301 return NS_OK; 302 } 303 304 NS_IMETHODIMP 305 nsMozIconURI::GetPrePath(nsACString& prePath) { 306 prePath = MOZICON_SCHEME; 307 return NS_OK; 308 } 309 310 NS_IMETHODIMP 311 nsMozIconURI::GetScheme(nsACString& aScheme) { 312 aScheme = "moz-icon"; 313 return NS_OK; 314 } 315 316 nsresult nsMozIconURI::SetScheme(const nsACString& aScheme) { 317 // doesn't make sense to set the scheme of a moz-icon URL 318 return NS_ERROR_FAILURE; 319 } 320 321 NS_IMETHODIMP 322 nsMozIconURI::GetUsername(nsACString& aUsername) { return NS_ERROR_FAILURE; } 323 324 nsresult nsMozIconURI::SetUsername(const nsACString& aUsername) { 325 return NS_ERROR_FAILURE; 326 } 327 328 NS_IMETHODIMP 329 nsMozIconURI::GetPassword(nsACString& aPassword) { return NS_ERROR_FAILURE; } 330 331 nsresult nsMozIconURI::SetPassword(const nsACString& aPassword) { 332 return NS_ERROR_FAILURE; 333 } 334 335 NS_IMETHODIMP 336 nsMozIconURI::GetUserPass(nsACString& aUserPass) { return NS_ERROR_FAILURE; } 337 338 nsresult nsMozIconURI::SetUserPass(const nsACString& aUserPass) { 339 return NS_ERROR_FAILURE; 340 } 341 342 NS_IMETHODIMP 343 nsMozIconURI::GetHostPort(nsACString& aHostPort) { return NS_ERROR_FAILURE; } 344 345 nsresult nsMozIconURI::SetHostPort(const nsACString& aHostPort) { 346 return NS_ERROR_FAILURE; 347 } 348 349 NS_IMETHODIMP 350 nsMozIconURI::GetHost(nsACString& aHost) { return NS_ERROR_FAILURE; } 351 352 nsresult nsMozIconURI::SetHost(const nsACString& aHost) { 353 return NS_ERROR_FAILURE; 354 } 355 356 NS_IMETHODIMP 357 nsMozIconURI::GetPort(int32_t* aPort) { return NS_ERROR_FAILURE; } 358 359 nsresult nsMozIconURI::SetPort(int32_t aPort) { return NS_ERROR_FAILURE; } 360 361 NS_IMETHODIMP 362 nsMozIconURI::GetPathQueryRef(nsACString& aPath) { 363 aPath.Truncate(); 364 return NS_OK; 365 } 366 367 nsresult nsMozIconURI::SetPathQueryRef(const nsACString& aPath) { 368 return NS_ERROR_FAILURE; 369 } 370 371 NS_IMETHODIMP 372 nsMozIconURI::GetFilePath(nsACString& aFilePath) { 373 aFilePath.Truncate(); 374 return NS_OK; 375 } 376 377 nsresult nsMozIconURI::SetFilePath(const nsACString& aFilePath) { 378 return NS_ERROR_FAILURE; 379 } 380 381 NS_IMETHODIMP 382 nsMozIconURI::GetQuery(nsACString& aQuery) { 383 aQuery.Truncate(); 384 return NS_OK; 385 } 386 387 nsresult nsMozIconURI::SetQuery(const nsACString& aQuery) { 388 return NS_ERROR_FAILURE; 389 } 390 391 nsresult nsMozIconURI::SetQueryWithEncoding(const nsACString& aQuery, 392 const Encoding* aEncoding) { 393 return NS_ERROR_FAILURE; 394 } 395 396 NS_IMETHODIMP 397 nsMozIconURI::GetRef(nsACString& aRef) { 398 aRef.Truncate(); 399 return NS_OK; 400 } 401 402 nsresult nsMozIconURI::SetRef(const nsACString& aRef) { 403 return NS_ERROR_FAILURE; 404 } 405 406 NS_IMETHODIMP 407 nsMozIconURI::Equals(nsIURI* other, bool* result) { 408 *result = false; 409 NS_ENSURE_ARG_POINTER(other); 410 MOZ_ASSERT(result, "null pointer"); 411 412 nsAutoCString spec1; 413 nsAutoCString spec2; 414 415 nsresult rv = GetSpec(spec1); 416 NS_ENSURE_SUCCESS(rv, rv); 417 rv = other->GetSpec(spec2); 418 NS_ENSURE_SUCCESS(rv, rv); 419 420 if (!nsCRT::strcasecmp(spec1.get(), spec2.get())) { 421 *result = true; 422 } else { 423 *result = false; 424 } 425 return NS_OK; 426 } 427 428 NS_IMETHODIMP 429 nsMozIconURI::EqualsExceptRef(nsIURI* other, bool* result) { 430 // GetRef/SetRef not supported by nsMozIconURI, so 431 // EqualsExceptRef() is the same as Equals(). 432 return Equals(other, result); 433 } 434 435 NS_IMETHODIMP 436 nsMozIconURI::SchemeIs(const char* aScheme, bool* aEquals) { 437 MOZ_ASSERT(aEquals, "null pointer"); 438 if (!aScheme) { 439 *aEquals = false; 440 return NS_OK; 441 } 442 443 *aEquals = nsCRT::strcasecmp("moz-icon", aScheme) == 0; 444 return NS_OK; 445 } 446 447 nsresult nsMozIconURI::Clone(nsIURI** result) { 448 nsCOMPtr<nsIURL> newIconURL; 449 if (mIconURL) { 450 newIconURL = mIconURL; 451 } 452 453 RefPtr<nsMozIconURI> uri = new nsMozIconURI(); 454 newIconURL.swap(uri->mIconURL); 455 uri->mSize = mSize; 456 uri->mContentType = mContentType; 457 uri->mFileName = mFileName; 458 uri->mStockIcon = mStockIcon; 459 uri.forget(result); 460 461 return NS_OK; 462 } 463 464 NS_IMETHODIMP 465 nsMozIconURI::Resolve(const nsACString& relativePath, nsACString& result) { 466 return NS_ERROR_NOT_IMPLEMENTED; 467 } 468 469 NS_IMETHODIMP 470 nsMozIconURI::GetAsciiSpec(nsACString& aSpecA) { return GetSpec(aSpecA); } 471 472 NS_IMETHODIMP 473 nsMozIconURI::GetAsciiHostPort(nsACString& aHostPortA) { 474 return GetHostPort(aHostPortA); 475 } 476 477 NS_IMETHODIMP 478 nsMozIconURI::GetAsciiHost(nsACString& aHostA) { return GetHost(aHostA); } 479 480 //////////////////////////////////////////////////////////////////////////////// 481 // nsIIconUri methods: 482 483 NS_IMETHODIMP 484 nsMozIconURI::GetIconURL(nsIURL** aFileUrl) { 485 *aFileUrl = mIconURL; 486 NS_IF_ADDREF(*aFileUrl); 487 return NS_OK; 488 } 489 490 NS_IMETHODIMP 491 nsMozIconURI::GetImageSize(uint32_t* aImageSize) { 492 *aImageSize = mSize; 493 return NS_OK; 494 } 495 496 NS_IMETHODIMP 497 nsMozIconURI::GetImageScale(uint32_t* aImageScale) { 498 *aImageScale = mScale; 499 return NS_OK; 500 } 501 502 NS_IMETHODIMP 503 nsMozIconURI::GetImageDark(bool* aImageDark) { 504 if (!mDark) { 505 return NS_ERROR_FAILURE; 506 } 507 *aImageDark = *mDark; 508 return NS_OK; 509 } 510 511 NS_IMETHODIMP 512 nsMozIconURI::GetContentType(nsACString& aContentType) { 513 aContentType = mContentType; 514 return NS_OK; 515 } 516 517 NS_IMETHODIMP 518 nsMozIconURI::GetFileExtension(nsACString& aFileExtension) { 519 // First, try to get the extension from mIconURL if we have one 520 if (mIconURL) { 521 nsAutoCString fileExt; 522 if (NS_SUCCEEDED(mIconURL->GetFileExtension(fileExt))) { 523 if (!fileExt.IsEmpty()) { 524 // unfortunately, this code doesn't give us the required '.' in 525 // front of the extension so we have to do it ourselves. 526 aFileExtension.Assign('.'); 527 aFileExtension.Append(fileExt); 528 } 529 } 530 return NS_OK; 531 } 532 533 if (!mFileName.IsEmpty()) { 534 // truncate the extension out of the file path... 535 const char* chFileName = mFileName.get(); // get the underlying buffer 536 const char* fileExt = strrchr(chFileName, '.'); 537 if (!fileExt) { 538 return NS_OK; 539 } 540 aFileExtension = fileExt; 541 } 542 543 return NS_OK; 544 } 545 546 NS_IMETHODIMP 547 nsMozIconURI::GetStockIcon(nsACString& aStockIcon) { 548 aStockIcon = mStockIcon; 549 return NS_OK; 550 } 551 552 void nsMozIconURI::Serialize(URIParams& aParams) { 553 IconURIParams params; 554 555 if (mIconURL) { 556 URIParams iconURLParams; 557 SerializeURI(mIconURL, iconURLParams); 558 if (iconURLParams.type() == URIParams::T__None) { 559 // Serialization failed, bail. 560 return; 561 } 562 563 params.uri() = Some(std::move(iconURLParams)); 564 } else { 565 params.uri() = Nothing(); 566 } 567 568 params.size() = mSize; 569 params.contentType() = mContentType; 570 params.fileName() = mFileName; 571 params.stockIcon() = mStockIcon; 572 573 params.iconScale() = mScale; 574 params.iconDark() = mDark; 575 576 aParams = params; 577 } 578 579 bool nsMozIconURI::Deserialize(const URIParams& aParams) { 580 if (aParams.type() != URIParams::TIconURIParams) { 581 MOZ_ASSERT_UNREACHABLE("Received unknown URI from other process!"); 582 return false; 583 } 584 585 const IconURIParams& params = aParams.get_IconURIParams(); 586 if (params.uri().isSome()) { 587 nsCOMPtr<nsIURI> uri = DeserializeURI(params.uri().ref()); 588 mIconURL = do_QueryInterface(uri); 589 if (!mIconURL) { 590 MOZ_ASSERT_UNREACHABLE("bad nsIURI passed"); 591 return false; 592 } 593 } 594 595 mSize = params.size(); 596 mContentType = params.contentType(); 597 mFileName = params.fileName(); 598 mStockIcon = params.stockIcon(); 599 600 mScale = params.iconScale(); 601 mDark = params.iconDark(); 602 603 return true; 604 } 605 606 size_t nsMozIconURI::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { 607 // We don't need to calculate this unless it shows up in DMD. 608 return 0; 609 }; 610 611 NS_IMETHODIMP 612 nsMozIconURI::GetInnerURI(nsIURI** aURI) { 613 nsCOMPtr<nsIURI> iconURL = mIconURL; 614 if (!iconURL) { 615 *aURI = nullptr; 616 return NS_ERROR_FAILURE; 617 } 618 619 iconURL.forget(aURI); 620 return NS_OK; 621 } 622 623 NS_IMETHODIMP 624 nsMozIconURI::GetInnermostURI(nsIURI** aURI) { 625 return NS_ImplGetInnermostURI(this, aURI); 626 } 627 628 NS_IMETHODIMP 629 nsMozIconURI::Read(nsIObjectInputStream* aStream) { 630 MOZ_ASSERT_UNREACHABLE("Use nsIURIMutator.read() instead"); 631 return NS_ERROR_NOT_IMPLEMENTED; 632 } 633 634 nsresult nsMozIconURI::ReadPrivate(nsIObjectInputStream* aStream) { 635 nsAutoCString spec; 636 nsresult rv = aStream->ReadCString(spec); 637 NS_ENSURE_SUCCESS(rv, rv); 638 return SetSpecInternal(spec); 639 } 640 641 NS_IMETHODIMP 642 nsMozIconURI::Write(nsIObjectOutputStream* aStream) { 643 nsAutoCString spec; 644 nsresult rv = GetSpec(spec); 645 NS_ENSURE_SUCCESS(rv, rv); 646 return aStream->WriteStringZ(spec.get()); 647 }