LCOV - code coverage report
Current view: top level - dom/html/input - SingleLineTextInputTypes.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 8 119 6.7 %
Date: 2017-07-14 16:53:18 Functions: 4 16 25.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "SingleLineTextInputTypes.h"
       8             : 
       9             : #include "mozilla/dom/HTMLInputElement.h"
      10             : #include "mozilla/dom/BindingDeclarations.h"
      11             : #include "HTMLSplitOnSpacesTokenizer.h"
      12             : #include "nsContentUtils.h"
      13             : #include "nsCRTGlue.h"
      14             : #include "nsIIDNService.h"
      15             : #include "nsIIOService.h"
      16             : #include "nsNetCID.h"
      17             : #include "nsNetUtil.h"
      18             : 
      19             : bool
      20           0 : SingleLineTextInputTypeBase::IsMutable() const
      21             : {
      22           0 :   return !mInputElement->IsDisabled() &&
      23           0 :          !mInputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly);
      24             : }
      25             : 
      26             : bool
      27           0 : SingleLineTextInputTypeBase::IsTooLong() const
      28             : {
      29           0 :   int32_t maxLength = mInputElement->MaxLength();
      30             : 
      31             :   // Maxlength of -1 means attribute isn't set or parsing error.
      32           0 :   if (maxLength == -1) {
      33           0 :    return false;
      34             :   }
      35             : 
      36             :   int32_t textLength =
      37           0 :     mInputElement->InputTextLength(mozilla::dom::CallerType::System);
      38             : 
      39           0 :   return textLength > maxLength;
      40             : }
      41             : 
      42             : bool
      43           0 : SingleLineTextInputTypeBase::IsTooShort() const
      44             : {
      45           0 :   int32_t minLength = mInputElement->MinLength();
      46             : 
      47             :   // Minlength of -1 means attribute isn't set or parsing error.
      48           0 :   if (minLength == -1) {
      49           0 :     return false;
      50             :   }
      51             : 
      52             :   int32_t textLength =
      53           0 :     mInputElement->InputTextLength(mozilla::dom::CallerType::System);
      54             : 
      55           0 :   return textLength && textLength < minLength;
      56             : }
      57             : 
      58             : bool
      59          30 : SingleLineTextInputTypeBase::IsValueMissing() const
      60             : {
      61          30 :   if (!mInputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
      62          30 :     return false;
      63             :   }
      64             : 
      65           0 :   if (!IsMutable()) {
      66           0 :     return false;
      67             :   }
      68             : 
      69           0 :   return IsValueEmpty();
      70             : }
      71             : 
      72             : bool
      73           7 : SingleLineTextInputTypeBase::HasPatternMismatch() const
      74             : {
      75          14 :   nsAutoString pattern;
      76           7 :  if (!mInputElement->GetAttr(kNameSpaceID_None, nsGkAtoms::pattern, pattern)) {
      77           7 :     return false;
      78             :   }
      79             : 
      80           0 :   nsAutoString value;
      81           0 :   GetNonFileValueInternal(value);
      82             : 
      83           0 :   if (value.IsEmpty()) {
      84           0 :     return false;
      85             :   }
      86             : 
      87           0 :   nsIDocument* doc = mInputElement->OwnerDoc();
      88             : 
      89           0 :   return !nsContentUtils::IsPatternMatching(value, pattern, doc);
      90             : }
      91             : 
      92             : /* input type=url */
      93             : 
      94             : bool
      95           0 : URLInputType::HasTypeMismatch() const
      96             : {
      97           0 :   nsAutoString value;
      98           0 :   GetNonFileValueInternal(value);
      99             : 
     100           0 :   if (value.IsEmpty()) {
     101           0 :     return false;
     102             :   }
     103             : 
     104             :   /**
     105             :    * TODO:
     106             :    * The URL is not checked as the HTML5 specifications want it to be because
     107             :    * there is no code to check for a valid URI/IRI according to 3986 and 3987
     108             :    * RFC's at the moment, see bug 561586.
     109             :    *
     110             :    * RFC 3987 (IRI) implementation: bug 42899
     111             :    *
     112             :    * HTML5 specifications:
     113             :    * http://dev.w3.org/html5/spec/infrastructure.html#valid-url
     114             :    */
     115           0 :   nsCOMPtr<nsIIOService> ioService = do_GetIOService();
     116           0 :   nsCOMPtr<nsIURI> uri;
     117             : 
     118           0 :   return !NS_SUCCEEDED(ioService->NewURI(NS_ConvertUTF16toUTF8(value), nullptr,
     119             :                                          nullptr, getter_AddRefs(uri)));
     120             : 
     121             : }
     122             : 
     123             : nsresult
     124           0 : URLInputType::GetTypeMismatchMessage(nsXPIDLString& aMessage)
     125             : {
     126             :   return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     127             :                                             "FormValidationInvalidURL",
     128           0 :                                             aMessage);
     129             : }
     130             : 
     131             : /* input type=email */
     132             : 
     133             : bool
     134           0 : EmailInputType::HasTypeMismatch() const
     135             : {
     136           0 :   nsAutoString value;
     137           0 :   GetNonFileValueInternal(value);
     138             : 
     139           0 :   if (value.IsEmpty()) {
     140           0 :     return false;
     141             :   }
     142             : 
     143           0 :   return mInputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple) ?
     144           0 :     !IsValidEmailAddressList(value) : !IsValidEmailAddress(value);
     145             : }
     146             : 
     147             : bool
     148           0 : EmailInputType::HasBadInput() const
     149             : {
     150             :   // With regards to suffering from bad input the spec says that only the
     151             :   // punycode conversion works, so we don't care whether the email address is
     152             :   // valid or not here. (If the email address is invalid then we will be
     153             :   // suffering from a type mismatch.)
     154           0 :   nsAutoString value;
     155           0 :   nsAutoCString unused;
     156             :   uint32_t unused2;
     157           0 :   GetNonFileValueInternal(value);
     158           0 :   HTMLSplitOnSpacesTokenizer tokenizer(value, ',');
     159           0 :   while (tokenizer.hasMoreTokens()) {
     160           0 :     if (!PunycodeEncodeEmailAddress(tokenizer.nextToken(), unused, &unused2)) {
     161           0 :       return true;
     162             :     }
     163             :   }
     164           0 :   return false;
     165             : }
     166             : 
     167             : nsresult
     168           0 : EmailInputType::GetTypeMismatchMessage(nsXPIDLString& aMessage)
     169             : {
     170             :   return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     171             :                                             "FormValidationInvalidEmail",
     172           0 :                                             aMessage);
     173             : }
     174             : 
     175             : nsresult
     176           0 : EmailInputType::GetBadInputMessage(nsXPIDLString& aMessage)
     177             : {
     178             :   return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     179             :                                             "FormValidationInvalidEmail",
     180           0 :                                             aMessage);
     181             : }
     182             : 
     183             : /* static */ bool
     184           0 : EmailInputType::IsValidEmailAddressList(const nsAString& aValue)
     185             : {
     186           0 :   HTMLSplitOnSpacesTokenizer tokenizer(aValue, ',');
     187             : 
     188           0 :   while (tokenizer.hasMoreTokens()) {
     189           0 :     if (!IsValidEmailAddress(tokenizer.nextToken())) {
     190           0 :       return false;
     191             :     }
     192             :   }
     193             : 
     194           0 :   return !tokenizer.separatorAfterCurrentToken();
     195             : }
     196             : 
     197             : /* static */ bool
     198           0 : EmailInputType::IsValidEmailAddress(const nsAString& aValue)
     199             : {
     200             :   // Email addresses can't be empty and can't end with a '.' or '-'.
     201           0 :   if (aValue.IsEmpty() || aValue.Last() == '.' || aValue.Last() == '-') {
     202           0 :     return false;
     203             :   }
     204             : 
     205             :   uint32_t atPos;
     206           0 :   nsAutoCString value;
     207           0 :   if (!PunycodeEncodeEmailAddress(aValue, value, &atPos) ||
     208           0 :       atPos == (uint32_t)kNotFound || atPos == 0 || atPos == value.Length() - 1) {
     209             :     // Could not encode, or "@" was not found, or it was at the start or end
     210             :     // of the input - in all cases, not a valid email address.
     211           0 :     return false;
     212             :   }
     213             : 
     214           0 :   uint32_t length = value.Length();
     215           0 :   uint32_t i = 0;
     216             : 
     217             :   // Parsing the username.
     218           0 :   for (; i < atPos; ++i) {
     219           0 :     char16_t c = value[i];
     220             : 
     221             :     // The username characters have to be in this list to be valid.
     222           0 :     if (!(nsCRT::IsAsciiAlpha(c) || nsCRT::IsAsciiDigit(c) ||
     223           0 :           c == '.' || c == '!' || c == '#' || c == '$' || c == '%' ||
     224           0 :           c == '&' || c == '\''|| c == '*' || c == '+' || c == '-' ||
     225           0 :           c == '/' || c == '=' || c == '?' || c == '^' || c == '_' ||
     226           0 :           c == '`' || c == '{' || c == '|' || c == '}' || c == '~' )) {
     227           0 :       return false;
     228             :     }
     229             :   }
     230             : 
     231             :   // Skip the '@'.
     232           0 :   ++i;
     233             : 
     234             :   // The domain name can't begin with a dot or a dash.
     235           0 :   if (value[i] == '.' || value[i] == '-') {
     236           0 :     return false;
     237             :   }
     238             : 
     239             :   // Parsing the domain name.
     240           0 :   for (; i < length; ++i) {
     241           0 :     char16_t c = value[i];
     242             : 
     243           0 :     if (c == '.') {
     244             :       // A dot can't follow a dot or a dash.
     245           0 :       if (value[i-1] == '.' || value[i-1] == '-') {
     246           0 :         return false;
     247             :       }
     248           0 :     } else if (c == '-'){
     249             :       // A dash can't follow a dot.
     250           0 :       if (value[i-1] == '.') {
     251           0 :         return false;
     252             :       }
     253           0 :     } else if (!(nsCRT::IsAsciiAlpha(c) || nsCRT::IsAsciiDigit(c) ||
     254             :                  c == '-')) {
     255             :       // The domain characters have to be in this list to be valid.
     256           0 :       return false;
     257             :     }
     258             :   }
     259             : 
     260           0 :   return true;
     261             : }
     262             : 
     263             : /* static */ bool
     264           0 : EmailInputType::PunycodeEncodeEmailAddress(const nsAString& aEmail,
     265             :                                            nsAutoCString& aEncodedEmail,
     266             :                                            uint32_t* aIndexOfAt)
     267             : {
     268           0 :   nsAutoCString value = NS_ConvertUTF16toUTF8(aEmail);
     269           0 :   *aIndexOfAt = (uint32_t)value.FindChar('@');
     270             : 
     271           0 :   if (*aIndexOfAt == (uint32_t)kNotFound ||
     272           0 :       *aIndexOfAt == value.Length() - 1) {
     273           0 :     aEncodedEmail = value;
     274           0 :     return true;
     275             :   }
     276             : 
     277           0 :   nsCOMPtr<nsIIDNService> idnSrv = do_GetService(NS_IDNSERVICE_CONTRACTID);
     278           0 :   if (!idnSrv) {
     279           0 :     NS_ERROR("nsIIDNService isn't present!");
     280           0 :     return false;
     281             :   }
     282             : 
     283           0 :   uint32_t indexOfDomain = *aIndexOfAt + 1;
     284             : 
     285           0 :   const nsDependentCSubstring domain = Substring(value, indexOfDomain);
     286             :   bool ace;
     287           0 :   if (NS_SUCCEEDED(idnSrv->IsACE(domain, &ace)) && !ace) {
     288           0 :     nsAutoCString domainACE;
     289           0 :     if (NS_FAILED(idnSrv->ConvertUTF8toACE(domain, domainACE))) {
     290           0 :       return false;
     291             :     }
     292           0 :     value.Replace(indexOfDomain, domain.Length(), domainACE);
     293             :   }
     294             : 
     295           0 :   aEncodedEmail = value;
     296           0 :   return true;
     297           9 : }

Generated by: LCOV version 1.13