Example #1
0
static HTTPHeaderMap parseRFC822HeaderFields(const char* bytes, unsigned length)
{
    String lastHeaderKey;
    HTTPHeaderMap headerFields;

    // Loop over lines until we're past the header, or we can't find any more end-of-lines
    while (const char* endOfLine = findEndOfLine(bytes, length)) {
        const char* line = bytes;
        int lineLength = endOfLine - bytes;

        // Move bytes to the character after the terminator as returned by findEndOfLine.
        bytes = endOfLine + 1;
        if ((*endOfLine == '\r') && (*bytes == '\n'))
            bytes++; // Safe since findEndOfLine won't return a spanning CRLF.

        length -= (bytes - line);
        if (!lineLength) {
            // Blank line; we're at the end of the header
            break;
        }

        if (*line == ' ' || *line == '\t') {
            // Continuation of the previous header
            if (lastHeaderKey.isNull()) {
                // malformed header; ignore it and continue
                continue;
            } 
            
            // Merge the continuation of the previous header
            String currentValue = headerFields.get(lastHeaderKey);
            String newValue(line, lineLength);
            
            headerFields.set(lastHeaderKey, currentValue + newValue);
        } else {
            // Brand new header
            const char* colon = line;
            while (*colon != ':' && colon != endOfLine)
                colon++;

            if (colon == endOfLine) {
                // malformed header; ignore it and continue
                continue;
            }

            lastHeaderKey = capitalizeRFC822HeaderFieldName(String(line, colon - line));
            String value;
            
            for (colon++; colon != endOfLine; colon++) {
                if (*colon != ' ' && *colon != '\t')
                    break;
            }
            if (colon == endOfLine)
                value = "";
            else
                value = String(colon, endOfLine - colon);
            
            String oldValue = headerFields.get(lastHeaderKey);
            if (!oldValue.isNull()) {
                String tmp = oldValue;
                tmp += ", ";
                tmp += value;
                value = tmp;
            }
            
            headerFields.set(lastHeaderKey, value);
        }
    }

    return headerFields;
}
Example #2
0
void XMLTokenizer::startElementNs(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int nb_namespaces,
                                  const xmlChar** libxmlNamespaces, int nb_attributes, int nb_defaulted, const xmlChar** libxmlAttributes)
{
    if (m_parserStopped)
        return;
    
    if (m_parserPaused) {
        m_pendingCallbacks->appendStartElementNSCallback(xmlLocalName, xmlPrefix, xmlURI, nb_namespaces, libxmlNamespaces,
                                                         nb_attributes, nb_defaulted, libxmlAttributes);
        return;
    }
    
    m_sawFirstElement = true;

    exitText();

    String localName = toString(xmlLocalName);
    String uri = toString(xmlURI);
    String prefix = toString(xmlPrefix);

    if (m_parsingFragment && uri.isNull()) {
        if (!prefix.isNull())
            uri = m_prefixToNamespaceMap.get(prefix);
        else
            uri = m_defaultNamespaceURI;
    }

    ExceptionCode ec = 0;
    QualifiedName qName(prefix, localName, uri);
    RefPtr<Element> newElement = m_doc->createElement(qName, true, ec);
    if (!newElement) {
        stopParsing();
        return;
    }
    
    handleElementNamespaces(newElement.get(), libxmlNamespaces, nb_namespaces, ec);
    if (ec) {
        stopParsing();
        return;
    }

    ScriptController* jsProxy = m_doc->frame() ? m_doc->frame()->script() : 0;
    if (jsProxy && m_doc->frame()->script()->isEnabled())
        jsProxy->setEventHandlerLineno(lineNumber());

    handleElementAttributes(newElement.get(), libxmlAttributes, nb_attributes, ec);
    if (ec) {
        stopParsing();
        return;
    }

    if (jsProxy)
        jsProxy->setEventHandlerLineno(0);

    newElement->beginParsingChildren();

    if (isScriptElement(newElement.get()))
        m_scriptStartLine = lineNumber();

    if (!m_currentNode->addChild(newElement.get())) {
        stopParsing();
        return;
    }

    setCurrentNode(newElement.get());
    if (m_view && !newElement->attached())
        newElement->attach();
}
Example #3
0
JSValue jsStringOrUndefined(ExecState* exec, const String& s)
{
    if (s.isNull())
        return jsUndefined();
    return jsStringWithCache(exec, s);
}
Example #4
0
v8::Handle<v8::Value> v8StringOrUndefined(const String& str)
{
    return str.isNull() ? v8::Handle<v8::Value>(v8::Undefined()) : v8::Handle<v8::Value>(v8String(str));
}
Example #5
0
bool WebChromeClient::shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename)
{
    generatedFilename = m_page->injectedBundleUIClient().shouldGenerateFileForUpload(m_page, path);
    return !generatedFilename.isNull();
}
Example #6
0
size_t parseHTTPHeader(const char* start, size_t length, String& failureReason, AtomicString& nameStr, String& valueStr, bool strict)
{
    const char* p = start;
    const char* end = start + length;

    Vector<char> name;
    Vector<char> value;
    nameStr = AtomicString();
    valueStr = String();

    for (; p < end; p++) {
        switch (*p) {
        case '\r':
            if (name.isEmpty()) {
                if (p + 1 < end && *(p + 1) == '\n')
                    return (p + 2) - start;
                failureReason = "CR doesn't follow LF at " + trimInputSample(p, end - p);
                return 0;
            }
            failureReason = "Unexpected CR in name at " + trimInputSample(name.data(), name.size());
            return 0;
        case '\n':
            failureReason = "Unexpected LF in name at " + trimInputSample(name.data(), name.size());
            return 0;
        case ':':
            break;
        default:
            name.append(*p);
            continue;
        }
        if (*p == ':') {
            ++p;
            break;
        }
    }

    for (; p < end && *p == 0x20; p++) { }

    for (; p < end; p++) {
        switch (*p) {
        case '\r':
            break;
        case '\n':
            if (strict) {
                failureReason = "Unexpected LF in value at " + trimInputSample(value.data(), value.size());
                return 0;
            }
            break;
        default:
            value.append(*p);
        }
        if (*p == '\r' || (!strict && *p == '\n')) {
            ++p;
            break;
        }
    }
    if (p >= end || (strict && *p != '\n')) {
        failureReason = "CR doesn't follow LF after value at " + trimInputSample(p, end - p);
        return 0;
    }
    nameStr = AtomicString::fromUTF8(name.data(), name.size());
    valueStr = String::fromUTF8(value.data(), value.size());
    if (nameStr.isNull()) {
        failureReason = "Invalid UTF-8 sequence in header name";
        return 0;
    }
    if (valueStr.isNull()) {
        failureReason = "Invalid UTF-8 sequence in header value";
        return 0;
    }
    return p - start;
}
Example #7
0
File* DataStreamWrapper::open(const String& filename, const String& mode,
                              int options, const Variant& context) {

  // @todo: check allow_url_include?

  const char* data = filename.data();
  int data_len = filename.length();
  bool base64 = false;
  if (strncmp(data, "data:", sizeof("data:") - 1)) {
    return nullptr;
  }
  data += sizeof("data:") - 1;
  data_len -= sizeof("data:") - 1;

  // RFC 2397 specifies 'data:' as the prefix,
  // but zend's PHP supports 'data://' as well
  if (data_len >= 2 && data[0] == '/' && data[1] == '/') {
    data_len -= 2;
    data += 2;
  }

  char* comma = (char*)memchr(data, ',', data_len);
  if (comma == nullptr) {
    raise_warning("rfc2397: missing comma");
    return nullptr;
  }

  if (comma != data) {
    // we have meta
    ssize_t meta_len = comma - data;
    data_len -= meta_len;
    char* semi = (char*)memchr(data, ';', meta_len);
    char* slash = (char*)memchr(data, '/', meta_len);

    if (!slash && !semi) {
      raise_warning("rfc2397: invalid meta data");
      return nullptr;
    }

    if (!semi) {
      // only media type (type/subtype,data)
      ssize_t media_len = comma - data;
      meta_len -= media_len;
      data += media_len;
    } else if (slash && slash < semi) {
      // media type + param (type/subtype;param,data)
      ssize_t media_len = semi - data;
      meta_len -= media_len;
      data += media_len;
    } else {
      // no media type (;base64,data)
      if (semi != data // ex. foo;base64,data
          || meta_len != sizeof(";base64") - 1 // ex. ;something,data
          || memcmp(data, ";base64",
                    sizeof(";base64") - 1)) { // ex. ;base65,data
          raise_warning("rfc2397: invalid meta data");
          return nullptr;
        }
    }

    assert(data == comma || data == semi);
    // eat parameters, and figure out if we have ';base64'
    while (semi && (data == semi)) {
      data++;
      meta_len--;
      char* equals = (char*)memchr(data, '=', meta_len);
      semi = (char*)memchr(data, ';', meta_len);
      if (!equals || (semi && semi < data)) {
        // no equals, so either 'base64' or its bad
        if (meta_len != sizeof("base64") - 1 ||
            memcmp(data, "base64", sizeof("base64")-1)) {
          raise_warning("rfc2396: invalid parameter");
          return nullptr;
        }
        // it's "base64", we're done
        base64 = true;
        meta_len -= sizeof("base64") - 1;
        data += sizeof("base64") - 1;
        break;
      }
      // there's a parameter
      if (semi) {
        meta_len -= semi - data + 1;
        data = semi;
      } /* else, we're done with meta */
    }
  }
  data = comma + 1;
  data_len -= 1;
  std::unique_ptr<MemFile> file;
  String decoded;

  if (base64) {
    decoded = string_base64_decode(data, data_len, true);
    if (decoded.isNull()) {
      raise_warning("unable to decode base64 data");
      return nullptr;
    }
  } else {
    decoded = url_decode(data, data_len);
  }
  file =
    std::unique_ptr<MemFile>(newres<MemFile>(decoded.data(), decoded.size()));
  return file.release();
}
Example #8
0
String StylePropertySet::getLayeredShorthandValue(const StylePropertyShorthand& shorthand) const
{
    String res;

    const unsigned size = shorthand.length();
    // Begin by collecting the properties into an array.
    Vector< RefPtr<CSSValue> > values(size);
    size_t numLayers = 0;

    for (unsigned i = 0; i < size; ++i) {
        values[i] = getPropertyCSSValue(shorthand.properties()[i]);
        if (values[i]) {
            if (values[i]->isValueList()) {
                CSSValueList* valueList = static_cast<CSSValueList*>(values[i].get());
                numLayers = max(valueList->length(), numLayers);
            } else
                numLayers = max<size_t>(1U, numLayers);
        }
    }

    // Now stitch the properties together.  Implicit initial values are flagged as such and
    // can safely be omitted.
    for (size_t i = 0; i < numLayers; i++) {
        String layerRes;
        bool useRepeatXShorthand = false;
        bool useRepeatYShorthand = false;
        bool useSingleWordShorthand = false;
        for (unsigned j = 0; j < size; j++) {
            RefPtr<CSSValue> value;
            if (values[j]) {
                if (values[j]->isValueList())
                    value = static_cast<CSSValueList*>(values[j].get())->item(i);
                else {
                    value = values[j];

                    // Color only belongs in the last layer.
                    if (shorthand.properties()[j] == CSSPropertyBackgroundColor) {
                        if (i != numLayers - 1)
                            value = 0;
                    } else if (i != 0) // Other singletons only belong in the first layer.
                        value = 0;
                }
            }

            // We need to report background-repeat as it was written in the CSS. If the property is implicit,
            // then it was written with only one value. Here we figure out which value that was so we can
            // report back correctly.
            if (shorthand.properties()[j] == CSSPropertyBackgroundRepeatX && isPropertyImplicit(shorthand.properties()[j])) {

                // BUG 49055: make sure the value was not reset in the layer check just above.
                if (j < size - 1 && shorthand.properties()[j + 1] == CSSPropertyBackgroundRepeatY && value) {
                    RefPtr<CSSValue> yValue;
                    RefPtr<CSSValue> nextValue = values[j + 1];
                    if (nextValue->isValueList())
                        yValue = static_cast<CSSValueList*>(nextValue.get())->itemWithoutBoundsCheck(i);
                    else
                        yValue = nextValue;

                    int xId = static_cast<CSSPrimitiveValue*>(value.get())->getIdent();
                    int yId = static_cast<CSSPrimitiveValue*>(yValue.get())->getIdent();
                    if (xId != yId) {
                        if (xId == CSSValueRepeat && yId == CSSValueNoRepeat) {
                            useRepeatXShorthand = true;
                            ++j;
                        } else if (xId == CSSValueNoRepeat && yId == CSSValueRepeat) {
                            useRepeatYShorthand = true;
                            continue;
                        }
                    } else {
                        useSingleWordShorthand = true;
                        ++j;
                    }
                }
            }

            if (value && !value->isImplicitInitialValue()) {
                if (!layerRes.isNull())
                    layerRes += " ";
                if (useRepeatXShorthand) {
                    useRepeatXShorthand = false;
                    layerRes += getValueName(CSSValueRepeatX);
                } else if (useRepeatYShorthand) {
                    useRepeatYShorthand = false;
                    layerRes += getValueName(CSSValueRepeatY);
                } else if (useSingleWordShorthand) {
                    useSingleWordShorthand = false;
                    layerRes += value->cssText();
                } else
                    layerRes += value->cssText();
            }
        }

        if (!layerRes.isNull()) {
            if (!res.isNull())
                res += ", ";
            res += layerRes;
        }
    }
    return res;
}
Example #9
0
String StylePropertySet::asText() const
{
    StringBuilder result;

    const CSSProperty* positionXProp = 0;
    const CSSProperty* positionYProp = 0;
    const CSSProperty* repeatXProp = 0;
    const CSSProperty* repeatYProp = 0;

    // FIXME: Stack-allocate the buffer for these BitVectors.
    BitVector shorthandPropertyUsed;
    BitVector shorthandPropertyAppeared;

    unsigned size = m_properties.size();
    for (unsigned n = 0; n < size; ++n) {
        const CSSProperty& prop = m_properties[n];
        CSSPropertyID propertyID = prop.id();
        CSSPropertyID shorthandPropertyID = CSSPropertyInvalid;

        switch (propertyID) {
        case CSSPropertyBackgroundPositionX:
            positionXProp = &prop;
            continue;
        case CSSPropertyBackgroundPositionY:
            positionYProp = &prop;
            continue;
        case CSSPropertyBackgroundRepeatX:
            repeatXProp = &prop;
            continue;
        case CSSPropertyBackgroundRepeatY:
            repeatYProp = &prop;
            continue;
        case CSSPropertyBorderWidth:
        case CSSPropertyBorderTopWidth:
        case CSSPropertyBorderRightWidth:
        case CSSPropertyBorderBottomWidth:
        case CSSPropertyBorderLeftWidth:
        case CSSPropertyBorderStyle:
        case CSSPropertyBorderTopStyle:
        case CSSPropertyBorderRightStyle:
        case CSSPropertyBorderBottomStyle:
        case CSSPropertyBorderLeftStyle:
        case CSSPropertyBorderColor:
        case CSSPropertyBorderTopColor:
        case CSSPropertyBorderRightColor:
        case CSSPropertyBorderBottomColor:
        case CSSPropertyBorderLeftColor:
            // FIXME: Deal with cases where only some of border-(top|right|bottom|left) are specified.
            shorthandPropertyID = CSSPropertyBorder;
            if (shorthandPropertyAppeared.get(CSSPropertyBorder - firstCSSProperty))
                break;
            for (unsigned i = 0; i < borderAbridgedShorthand().length() && shorthandPropertyID; i++) {
                const StylePropertyShorthand& shorthand = *(borderAbridgedShorthand().propertiesForInitialization()[i]);
                String commonValue;
                bool commonImportance = false;
                for (size_t j = 0; j < shorthand.length(); ++j) {
                    CSSPropertyID id = shorthand.properties()[j];
                    RefPtr<CSSValue> value = getPropertyCSSValue(id);
                    String currentValue = value ? value->cssText() : String();
                    bool isImportant = propertyIsImportant(id);
                    if (j && (currentValue != commonValue || commonImportance != isImportant)) {
                        shorthandPropertyID = CSSPropertyInvalid;
                        break;
                    }
                    if (!j) {
                        commonValue = currentValue;
                        commonImportance = isImportant;
                    }
                }
            }
            break;
        case CSSPropertyWebkitBorderHorizontalSpacing:
        case CSSPropertyWebkitBorderVerticalSpacing:
            shorthandPropertyID = CSSPropertyBorderSpacing;
            break;
        case CSSPropertyFontFamily:
        case CSSPropertyLineHeight:
        case CSSPropertyFontSize:
        case CSSPropertyFontStyle:
        case CSSPropertyFontVariant:
        case CSSPropertyFontWeight:
            // Don't use CSSPropertyFont because old UAs can't recognize them but are important for editing.
            break;
        case CSSPropertyListStyleType:
        case CSSPropertyListStylePosition:
        case CSSPropertyListStyleImage:
            shorthandPropertyID = CSSPropertyListStyle;
            break;
        case CSSPropertyMarginTop:
        case CSSPropertyMarginRight:
        case CSSPropertyMarginBottom:
        case CSSPropertyMarginLeft:
            shorthandPropertyID = CSSPropertyMargin;
            break;
        case CSSPropertyOutlineWidth:
        case CSSPropertyOutlineStyle:
        case CSSPropertyOutlineColor:
            shorthandPropertyID = CSSPropertyOutline;
            break;
        case CSSPropertyOverflowX:
        case CSSPropertyOverflowY:
            shorthandPropertyID = CSSPropertyOverflow;
            break;
        case CSSPropertyPaddingTop:
        case CSSPropertyPaddingRight:
        case CSSPropertyPaddingBottom:
        case CSSPropertyPaddingLeft:
            shorthandPropertyID = CSSPropertyPadding;
            break;
        case CSSPropertyWebkitAnimationName:
        case CSSPropertyWebkitAnimationDuration:
        case CSSPropertyWebkitAnimationTimingFunction:
        case CSSPropertyWebkitAnimationDelay:
        case CSSPropertyWebkitAnimationIterationCount:
        case CSSPropertyWebkitAnimationDirection:
        case CSSPropertyWebkitAnimationFillMode:
            shorthandPropertyID = CSSPropertyWebkitAnimation;
            break;
        case CSSPropertyWebkitFlexDirection:
        case CSSPropertyWebkitFlexWrap:
            shorthandPropertyID = CSSPropertyWebkitFlexFlow;
            break;
        case CSSPropertyWebkitMaskPositionX:
        case CSSPropertyWebkitMaskPositionY:
        case CSSPropertyWebkitMaskRepeatX:
        case CSSPropertyWebkitMaskRepeatY:
        case CSSPropertyWebkitMaskImage:
        case CSSPropertyWebkitMaskRepeat:
        case CSSPropertyWebkitMaskAttachment:
        case CSSPropertyWebkitMaskPosition:
        case CSSPropertyWebkitMaskClip:
        case CSSPropertyWebkitMaskOrigin:
            shorthandPropertyID = CSSPropertyWebkitMask;
            break;
        case CSSPropertyWebkitTransformOriginX:
        case CSSPropertyWebkitTransformOriginY:
        case CSSPropertyWebkitTransformOriginZ:
            shorthandPropertyID = CSSPropertyWebkitTransformOrigin;
            break;
        case CSSPropertyWebkitTransitionProperty:
        case CSSPropertyWebkitTransitionDuration:
        case CSSPropertyWebkitTransitionTimingFunction:
        case CSSPropertyWebkitTransitionDelay:
            shorthandPropertyID = CSSPropertyWebkitTransition;
            break;
        case CSSPropertyWebkitWrapFlow:
        case CSSPropertyWebkitWrapMargin:
        case CSSPropertyWebkitWrapPadding:
            shorthandPropertyID = CSSPropertyWebkitWrap;
            break;
        default:
            break;
        }

        String value;
        unsigned shortPropertyIndex = shorthandPropertyID - firstCSSProperty;
        if (shorthandPropertyID) {
            if (shorthandPropertyUsed.get(shortPropertyIndex))
                continue;
            if (!shorthandPropertyAppeared.get(shortPropertyIndex))
                value = getPropertyValue(shorthandPropertyID);
            shorthandPropertyAppeared.ensureSizeAndSet(shortPropertyIndex, numCSSProperties);
        }

        if (!value.isNull()) {
            propertyID = shorthandPropertyID;
            shorthandPropertyUsed.ensureSizeAndSet(shortPropertyIndex, numCSSProperties);
        } else
            value = prop.value()->cssText();

        if (value == "initial" && !CSSProperty::isInheritedProperty(propertyID))
            continue;

        result.append(getPropertyName(propertyID));
        result.append(": ");
        result.append(value);
        result.append(prop.isImportant() ? " !important" : "");
        result.append("; ");
    }

    // FIXME: This is a not-so-nice way to turn x/y positions into single background-position in output.
    // It is required because background-position-x/y are non-standard properties and WebKit generated output
    // would not work in Firefox (<rdar://problem/5143183>)
    // It would be a better solution if background-position was CSS_PAIR.
    if (positionXProp && positionYProp && positionXProp->isImportant() == positionYProp->isImportant()) {
        result.append("background-position: ");
        if (positionXProp->value()->isValueList() || positionYProp->value()->isValueList())
            result.append(getLayeredShorthandValue(backgroundPositionShorthand()));
        else {
            result.append(positionXProp->value()->cssText());
            result.append(" ");
            result.append(positionYProp->value()->cssText());
        }
        if (positionXProp->isImportant())
            result.append(" !important");
        result.append("; ");
    } else {
        if (positionXProp)
            result.append(positionXProp->cssText());
        if (positionYProp)
            result.append(positionYProp->cssText());
    }

    // FIXME: We need to do the same for background-repeat.
    if (repeatXProp && repeatYProp && repeatXProp->isImportant() == repeatYProp->isImportant()) {
        result.append("background-repeat: ");
        if (repeatXProp->value()->isValueList() || repeatYProp->value()->isValueList())
            result.append(getLayeredShorthandValue(backgroundRepeatShorthand()));
        else {
            result.append(repeatXProp->value()->cssText());
            result.append(" ");
            result.append(repeatYProp->value()->cssText());
        }
        if (repeatXProp->isImportant())
            result.append(" !important");
        result.append("; ");
    } else {
        if (repeatXProp)
            result.append(repeatXProp->cssText());
        if (repeatYProp)
            result.append(repeatYProp->cssText());
    }

    return result.toString();
}
Example #10
0
String StylePropertySet::asText() const
{
    StringBuilder result;

    const CSSProperty* positionXProp = 0;
    const CSSProperty* positionYProp = 0;
    const CSSProperty* repeatXProp = 0;
    const CSSProperty* repeatYProp = 0;

    BitArray<numCSSProperties> shorthandPropertyUsed;
    BitArray<numCSSProperties> shorthandPropertyAppeared;

    unsigned size = propertyCount();
    for (unsigned n = 0; n < size; ++n) {
        const CSSProperty& prop = propertyAt(n);
        CSSPropertyID propertyID = prop.id();
        CSSPropertyID shorthandPropertyID = CSSPropertyInvalid;
        CSSPropertyID borderFallbackShorthandProperty = CSSPropertyInvalid;
        String value;

        switch (propertyID) {
#if ENABLE(CSS_VARIABLES)
        case CSSPropertyVariable:
            result.append(prop.cssText());
            continue;
#endif
        case CSSPropertyBackgroundPositionX:
            positionXProp = &prop;
            continue;
        case CSSPropertyBackgroundPositionY:
            positionYProp = &prop;
            continue;
        case CSSPropertyBackgroundRepeatX:
            repeatXProp = &prop;
            continue;
        case CSSPropertyBackgroundRepeatY:
            repeatYProp = &prop;
            continue;
        case CSSPropertyBorderTopWidth:
        case CSSPropertyBorderRightWidth:
        case CSSPropertyBorderBottomWidth:
        case CSSPropertyBorderLeftWidth:
            if (!borderFallbackShorthandProperty)
                borderFallbackShorthandProperty = CSSPropertyBorderWidth;
        case CSSPropertyBorderTopStyle:
        case CSSPropertyBorderRightStyle:
        case CSSPropertyBorderBottomStyle:
        case CSSPropertyBorderLeftStyle:
            if (!borderFallbackShorthandProperty)
                borderFallbackShorthandProperty = CSSPropertyBorderStyle;
        case CSSPropertyBorderTopColor:
        case CSSPropertyBorderRightColor:
        case CSSPropertyBorderBottomColor:
        case CSSPropertyBorderLeftColor:
            if (!borderFallbackShorthandProperty)
                borderFallbackShorthandProperty = CSSPropertyBorderColor;

            // FIXME: Deal with cases where only some of border-(top|right|bottom|left) are specified.
            if (!shorthandPropertyAppeared.get(CSSPropertyBorder - firstCSSProperty)) {
                value = borderPropertyValue(ReturnNullOnUncommonValues);
                if (value.isNull())
                    shorthandPropertyAppeared.set(CSSPropertyBorder - firstCSSProperty);
                else
                    shorthandPropertyID = CSSPropertyBorder;
            } else if (shorthandPropertyUsed.get(CSSPropertyBorder - firstCSSProperty))
                shorthandPropertyID = CSSPropertyBorder;
            if (!shorthandPropertyID)
                shorthandPropertyID = borderFallbackShorthandProperty;
            break;
        case CSSPropertyWebkitBorderHorizontalSpacing:
        case CSSPropertyWebkitBorderVerticalSpacing:
            shorthandPropertyID = CSSPropertyBorderSpacing;
            break;
        case CSSPropertyFontFamily:
        case CSSPropertyLineHeight:
        case CSSPropertyFontSize:
        case CSSPropertyFontStyle:
        case CSSPropertyFontVariant:
        case CSSPropertyFontWeight:
            // Don't use CSSPropertyFont because old UAs can't recognize them but are important for editing.
            break;
        case CSSPropertyListStyleType:
        case CSSPropertyListStylePosition:
        case CSSPropertyListStyleImage:
            shorthandPropertyID = CSSPropertyListStyle;
            break;
        case CSSPropertyMarginTop:
        case CSSPropertyMarginRight:
        case CSSPropertyMarginBottom:
        case CSSPropertyMarginLeft:
            shorthandPropertyID = CSSPropertyMargin;
            break;
        case CSSPropertyOutlineWidth:
        case CSSPropertyOutlineStyle:
        case CSSPropertyOutlineColor:
            shorthandPropertyID = CSSPropertyOutline;
            break;
        case CSSPropertyOverflowX:
        case CSSPropertyOverflowY:
            shorthandPropertyID = CSSPropertyOverflow;
            break;
        case CSSPropertyPaddingTop:
        case CSSPropertyPaddingRight:
        case CSSPropertyPaddingBottom:
        case CSSPropertyPaddingLeft:
            shorthandPropertyID = CSSPropertyPadding;
            break;
        case CSSPropertyWebkitAnimationName:
        case CSSPropertyWebkitAnimationDuration:
        case CSSPropertyWebkitAnimationTimingFunction:
        case CSSPropertyWebkitAnimationDelay:
        case CSSPropertyWebkitAnimationIterationCount:
        case CSSPropertyWebkitAnimationDirection:
        case CSSPropertyWebkitAnimationFillMode:
            shorthandPropertyID = CSSPropertyWebkitAnimation;
            break;
#if ENABLE(CSS3_FLEXBOX)
        case CSSPropertyWebkitFlexDirection:
        case CSSPropertyWebkitFlexWrap:
            shorthandPropertyID = CSSPropertyWebkitFlexFlow;
            break;
        case CSSPropertyWebkitFlexBasis:
        case CSSPropertyWebkitFlexGrow:
        case CSSPropertyWebkitFlexShrink:
            shorthandPropertyID = CSSPropertyWebkitFlex;
            break;
#endif
        case CSSPropertyWebkitMaskPositionX:
        case CSSPropertyWebkitMaskPositionY:
        case CSSPropertyWebkitMaskRepeatX:
        case CSSPropertyWebkitMaskRepeatY:
        case CSSPropertyWebkitMaskImage:
        case CSSPropertyWebkitMaskRepeat:
        case CSSPropertyWebkitMaskAttachment:
        case CSSPropertyWebkitMaskPosition:
        case CSSPropertyWebkitMaskClip:
        case CSSPropertyWebkitMaskOrigin:
            shorthandPropertyID = CSSPropertyWebkitMask;
            break;
        case CSSPropertyWebkitTransformOriginX:
        case CSSPropertyWebkitTransformOriginY:
        case CSSPropertyWebkitTransformOriginZ:
            shorthandPropertyID = CSSPropertyWebkitTransformOrigin;
            break;
        case CSSPropertyWebkitTransitionProperty:
        case CSSPropertyWebkitTransitionDuration:
        case CSSPropertyWebkitTransitionTimingFunction:
        case CSSPropertyWebkitTransitionDelay:
            shorthandPropertyID = CSSPropertyWebkitTransition;
            break;
#if ENABLE(CSS_EXCLUSIONS)
        case CSSPropertyWebkitWrapFlow:
        case CSSPropertyWebkitWrapMargin:
        case CSSPropertyWebkitWrapPadding:
            shorthandPropertyID = CSSPropertyWebkitWrap;
            break;
#endif
        default:
            break;
        }

        unsigned shortPropertyIndex = shorthandPropertyID - firstCSSProperty;
        if (shorthandPropertyID) {
            if (shorthandPropertyUsed.get(shortPropertyIndex))
                continue;
            if (!shorthandPropertyAppeared.get(shortPropertyIndex) && value.isNull())
                value = getPropertyValue(shorthandPropertyID);
            shorthandPropertyAppeared.set(shortPropertyIndex);
        }

        if (!value.isNull()) {
            propertyID = shorthandPropertyID;
            shorthandPropertyUsed.set(shortPropertyIndex);
        } else
            value = prop.value()->cssText();

        if (value == "initial" && !CSSProperty::isInheritedProperty(propertyID))
            continue;

        result.append(getPropertyName(propertyID));
        result.append(": ");
        result.append(value);
        result.append(prop.isImportant() ? " !important" : "");
        result.append("; ");
    }

    // FIXME: This is a not-so-nice way to turn x/y positions into single background-position in output.
    // It is required because background-position-x/y are non-standard properties and WebKit generated output
    // would not work in Firefox (<rdar://problem/5143183>)
    // It would be a better solution if background-position was CSS_PAIR.
    if (positionXProp && positionYProp && positionXProp->isImportant() == positionYProp->isImportant()) {
        result.append("background-position: ");
        if (positionXProp->value()->isValueList() || positionYProp->value()->isValueList())
            result.append(getLayeredShorthandValue(backgroundPositionShorthand()));
        else {
            result.append(positionXProp->value()->cssText());
            result.append(" ");
            result.append(positionYProp->value()->cssText());
        }
        if (positionXProp->isImportant())
            result.append(" !important");
        result.append("; ");
    } else {
        if (positionXProp)
            result.append(positionXProp->cssText());
        if (positionYProp)
            result.append(positionYProp->cssText());
    }

    // FIXME: We need to do the same for background-repeat.
    if (repeatXProp && repeatYProp && repeatXProp->isImportant() == repeatYProp->isImportant()) {
        result.append("background-repeat: ");
        if (repeatXProp->value()->isValueList() || repeatYProp->value()->isValueList())
            result.append(getLayeredShorthandValue(backgroundRepeatShorthand()));
        else {
            result.append(repeatXProp->value()->cssText());
            result.append(" ");
            result.append(repeatYProp->value()->cssText());
        }
        if (repeatXProp->isImportant())
            result.append(" !important");
        result.append("; ");
    } else {
        if (repeatXProp)
            result.append(repeatXProp->cssText());
        if (repeatYProp)
            result.append(repeatYProp->cssText());
    }

    return result.toString();
}
Example #11
0
void NetworkJob::sendResponseIfNeeded()
{
    if (m_responseSent)
        return;

    m_responseSent = true;

    if (shouldNotifyClientFailed())
        return;

    String urlFilename;
    if (!m_response.url().protocolIsData() && !m_response.url().protocolIs("about"))
        urlFilename = m_response.url().lastPathComponent();

    // Get the MIME type that was set by the content sniffer
    // if there's no custom sniffer header, try to set it from the Content-Type header
    // if this fails, guess it from extension.
    String mimeType = m_sniffedMimeType;
    if (m_isFTP && m_isFTPDir)
        mimeType = "application/x-ftp-directory";
    else if (mimeType.isNull())
        mimeType = extractMIMETypeFromMediaType(m_contentType);
    if (mimeType.isNull()) {
        if (m_dataReceived)
            mimeType = MIMETypeRegistry::getMIMETypeForPath(urlFilename);
        else
            // For empty content, we shouldn't download.
            mimeType = "text/plain";
    }
    m_response.setMimeType(mimeType);

    // Set encoding from Content-Type header.
    m_response.setTextEncodingName(extractCharsetFromMediaType(m_contentType));

    // Set content length from header.
    String contentLength = m_response.httpHeaderField("Content-Length");
    if (!contentLength.isNull())
        m_response.setExpectedContentLength(contentLength.toInt64());

    // Set suggested filename for downloads from the Content-Disposition header; if this fails,
    // fill it in from the url and sniffed mime type;Skip this for about URLs,
    // because they have no Content-Disposition header and the format is wrong to be a filename.
    if (!m_isAbout) {
        String suggestedFilename = filenameFromHTTPContentDisposition(m_contentDisposition);
        if (suggestedFilename.isEmpty()) {
            // Check and see if an extension already exists.
            String mimeExtension = MIMETypeRegistry::getPreferredExtensionForMIMEType(mimeType);
            if (urlFilename.isEmpty()) {
                if (mimeExtension.isEmpty()) // No extension found for the mimeType.
                    suggestedFilename = String(BlackBerry::Platform::LocalizeResource::getString(BlackBerry::Platform::FILENAME_UNTITLED));
                else
                    suggestedFilename = String(BlackBerry::Platform::LocalizeResource::getString(BlackBerry::Platform::FILENAME_UNTITLED)) + "." + mimeExtension;
            } else {
                if (urlFilename.reverseFind('.') == notFound && !mimeExtension.isEmpty())
                   suggestedFilename = urlFilename + '.' + mimeExtension;
                else
                   suggestedFilename = urlFilename;
            }
        }
        m_response.setSuggestedFilename(suggestedFilename);
    }

    // Don't cache resources for "about:"
    if (m_isAbout)
        m_response.setHTTPHeaderField("Cache-Control", "no-cache");

    if (isClientAvailable()) {
        RecursionGuard guard(m_callingClient);
        m_handle->client()->didReceiveResponse(m_handle.get(), m_response);
    }
}
Example #12
0
String f_gmstrftime(const String& format,
                    int64_t timestamp /* = TimeStamp::Current() */) {
  String ret = DateTime(timestamp, true).toString(format, true);
  if (ret.isNull()) return false;
  return ret;
}
Example #13
0
  void testString()
  {
    String s = "taglib string";
    ByteVector v = "taglib string";
    CPPUNIT_ASSERT(v == s.data(String::Latin1));

    char str[] = "taglib string";
    CPPUNIT_ASSERT(strcmp(s.toCString(), str) == 0);
    CPPUNIT_ASSERT(s == "taglib string");
    CPPUNIT_ASSERT(s != "taglib STRING");
    CPPUNIT_ASSERT(s != "taglib");
    CPPUNIT_ASSERT(s != "taglib string taglib");
    CPPUNIT_ASSERT(s == L"taglib string");
    CPPUNIT_ASSERT(s != L"taglib STRING");
    CPPUNIT_ASSERT(s != L"taglib");
    CPPUNIT_ASSERT(s != L"taglib string taglib");

    s.clear();
    CPPUNIT_ASSERT(s.isEmpty());
    CPPUNIT_ASSERT(!s.isNull()); // deprecated, but still worth it to check.

    String unicode("José Carlos", String::UTF8);
    CPPUNIT_ASSERT(strcmp(unicode.toCString(), "Jos\xe9 Carlos") == 0);

    String latin = "Jos\xe9 Carlos";
    CPPUNIT_ASSERT(strcmp(latin.toCString(true), "José Carlos") == 0);

    String c;
    c = "1";
    CPPUNIT_ASSERT(c == L"1");

    c = L'\u4E00';
    CPPUNIT_ASSERT(c == L"\u4E00");

    String unicode2(unicode.to8Bit(true), String::UTF8);
    CPPUNIT_ASSERT(unicode == unicode2);

    String unicode3(L"\u65E5\u672C\u8A9E");
    CPPUNIT_ASSERT(*(unicode3.toCWString() + 1) == L'\u672C');

    String unicode4(L"\u65e5\u672c\u8a9e", String::UTF16BE);
    CPPUNIT_ASSERT(unicode4[1] == L'\u672c');

    String unicode5(L"\u65e5\u672c\u8a9e", String::UTF16LE);
    CPPUNIT_ASSERT(unicode5[1] == L'\u2c67');

    std::wstring stduni = L"\u65e5\u672c\u8a9e";

    String unicode6(stduni, String::UTF16BE);
    CPPUNIT_ASSERT(unicode6[1] == L'\u672c');

    String unicode7(stduni, String::UTF16LE);
    CPPUNIT_ASSERT(unicode7[1] == L'\u2c67');

    CPPUNIT_ASSERT(String("  foo  ").stripWhiteSpace() == String("foo"));
    CPPUNIT_ASSERT(String("foo    ").stripWhiteSpace() == String("foo"));
    CPPUNIT_ASSERT(String("    foo").stripWhiteSpace() == String("foo"));

    CPPUNIT_ASSERT(memcmp(String("foo").data(String::Latin1).data(), "foo", 3) == 0);
    CPPUNIT_ASSERT(memcmp(String("f").data(String::Latin1).data(), "f", 1) == 0);
  }
Example #14
0
bool CurlCacheEntry::parseResponseHeaders(const ResourceResponse& response)
{
    double fileTime;
    time_t fileModificationDate;

    if (getFileModificationTime(m_headerFilename, fileModificationDate)) {
        fileTime = difftime(fileModificationDate, 0);
        fileTime *= 1000.0;
    } else
        fileTime = currentTimeMS(); // GMT

    if (response.cacheControlContainsNoCache() || response.cacheControlContainsNoStore())
        return false;


    double maxAge = 0;
    bool maxAgeIsValid = false;

    if (response.cacheControlContainsMustRevalidate())
        maxAge = 0;
    else {
        maxAge = response.cacheControlMaxAge();
        if (std::isnan(maxAge))
            maxAge = 0;
        else
            maxAgeIsValid = true;
    }

    if (!response.hasCacheValidatorFields())
        return false;


    double lastModificationDate = 0;
    double responseDate = 0;
    double expirationDate = 0;

    lastModificationDate = response.lastModified();
    if (std::isnan(lastModificationDate))
        lastModificationDate = 0;

    responseDate = response.date();
    if (std::isnan(responseDate))
        responseDate = 0;

    expirationDate = response.expires();
    if (std::isnan(expirationDate))
        expirationDate = 0;


    if (maxAgeIsValid) {
        // When both the cache entry and the response contain max-age, the lesser one takes priority
        double expires = fileTime + maxAge * 1000;
        if (m_expireDate == -1 || m_expireDate > expires)
            m_expireDate = expires;
    } else if (responseDate > 0 && expirationDate >= responseDate)
        m_expireDate = fileTime + (expirationDate - responseDate);

    // If there is no lifetime information
    if (m_expireDate == -1) {
        if (lastModificationDate > 0)
            m_expireDate = fileTime + (fileTime - lastModificationDate) * 0.1;
        else
            m_expireDate = 0;
    }

    String etag = response.httpHeaderField(HTTPHeaderName::ETag);
    if (!etag.isNull())
        m_requestHeaders.set(HTTPHeaderName::IfNoneMatch, etag);

    String lastModified = response.httpHeaderField(HTTPHeaderName::LastModified);
    if (!lastModified.isNull())
        m_requestHeaders.set(HTTPHeaderName::IfModifiedSince, lastModified);

    if (etag.isNull() && lastModified.isNull())
        return false;

    m_headerParsed = true;
    return true;
}
Example #15
0
void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceResponse& response)
{
    RefPtr<Host> protector(this);

    Request* request = m_requestsLoading.get(loader);
    
    // FIXME: This is a workaround for <rdar://problem/5236843>
    // If a load starts while the frame is still in the provisional state 
    // (this can be the case when loading the user style sheet), committing the load then causes all
    // requests to be removed from the m_requestsLoading map. This means that request might be null here.
    // In that case we just return early. 
    // ASSERT(request);
    if (!request)
        return;
    
    CachedResource* resource = request->cachedResource();
    
    if (resource->isCacheValidator()) {
        if (response.httpStatusCode() == 304) {
            // 304 Not modified / Use local copy
            m_requestsLoading.remove(loader);
            loader->clearClient();
            request->docLoader()->decrementRequestCount();

            // Existing resource is ok, just use it updating the expiration time.
            cache()->revalidationSucceeded(resource, response);
            
            if (request->docLoader()->frame())
                request->docLoader()->frame()->loader()->checkCompleted();

            delete request;

            servePendingRequests();
            return;
        } 
        // Did not get 304 response, continue as a regular resource load.
        cache()->revalidationFailed(resource);
    }

    resource->setResponse(response);

    String encoding = response.textEncodingName();
    if (!encoding.isNull())
        resource->setEncoding(encoding);
    
    if (request->isMultipart()) {
        ASSERT(resource->isImage());
        static_cast<CachedImage*>(resource)->clear();
        if (request->docLoader()->frame())
            request->docLoader()->frame()->loader()->checkCompleted();
    } else if (response.isMultipart()) {
        request->setIsMultipart(true);
        
        // We don't count multiParts in a DocLoader's request count
        request->docLoader()->decrementRequestCount();

        // If we get a multipart response, we must have a handle
        ASSERT(loader->handle());
        if (!resource->isImage())
            loader->handle()->cancel();
    }
}
Example #16
0
String StylePropertySet::getPropertyValue(CSSPropertyID propertyID) const
{
    RefPtr<CSSValue> value = getPropertyCSSValue(propertyID);
    if (value)
        return value->cssText();

    // Shorthand and 4-values properties
    switch (propertyID) {
    case CSSPropertyBorderSpacing:
        return borderSpacingValue(borderSpacingShorthand());
    case CSSPropertyBackgroundPosition:
        return getLayeredShorthandValue(backgroundPositionShorthand());
    case CSSPropertyBackgroundRepeat:
        return getLayeredShorthandValue(backgroundRepeatShorthand());
    case CSSPropertyBackground:
        return getLayeredShorthandValue(backgroundShorthand());
    case CSSPropertyBorder: {
        const StylePropertyShorthand properties[3] = { borderWidthShorthand(), borderStyleShorthand(), borderColorShorthand() };
        String res;
        for (size_t i = 0; i < WTF_ARRAY_LENGTH(properties); ++i) {
            String value = getCommonValue(properties[i]);
            if (!value.isNull()) {
                if (!res.isNull())
                    res += " ";
                res += value;
            }
        }
        return res;
    }
    case CSSPropertyBorderTop:
        return getShorthandValue(borderTopShorthand());
    case CSSPropertyBorderRight:
        return getShorthandValue(borderRightShorthand());
    case CSSPropertyBorderBottom:
        return getShorthandValue(borderBottomShorthand());
    case CSSPropertyBorderLeft:
        return getShorthandValue(borderLeftShorthand());
    case CSSPropertyOutline:
        return getShorthandValue(outlineShorthand());
    case CSSPropertyBorderColor:
        return get4Values(borderColorShorthand());
    case CSSPropertyBorderWidth:
        return get4Values(borderWidthShorthand());
    case CSSPropertyBorderStyle:
        return get4Values(borderStyleShorthand());
    case CSSPropertyWebkitFlexFlow:
        return getShorthandValue(webkitFlexFlowShorthand());
    case CSSPropertyFont:
        return fontValue();
    case CSSPropertyMargin:
        return get4Values(marginShorthand());
    case CSSPropertyOverflow:
        return getCommonValue(overflowShorthand());
    case CSSPropertyPadding:
        return get4Values(paddingShorthand());
    case CSSPropertyListStyle:
        return getShorthandValue(listStyleShorthand());
    case CSSPropertyWebkitMaskPosition:
        return getLayeredShorthandValue(webkitMaskPositionShorthand());
    case CSSPropertyWebkitMaskRepeat:
        return getLayeredShorthandValue(webkitMaskRepeatShorthand());
    case CSSPropertyWebkitMask:
        return getLayeredShorthandValue(webkitMaskShorthand());
    case CSSPropertyWebkitTransformOrigin:
        return getShorthandValue(webkitTransformOriginShorthand());
    case CSSPropertyWebkitTransition:
        return getLayeredShorthandValue(webkitTransitionShorthand());
    case CSSPropertyWebkitAnimation:
        return getLayeredShorthandValue(webkitAnimationShorthand());
    case CSSPropertyWebkitWrap:
        return getShorthandValue(webkitWrapShorthand());
#if ENABLE(SVG)
    case CSSPropertyMarker: {
        RefPtr<CSSValue> value = getPropertyCSSValue(CSSPropertyMarkerStart);
        if (value)
            return value->cssText();
    }
#endif
    case CSSPropertyBorderRadius:
        return get4Values(borderRadiusShorthand());
    default:
          return String();
    }
}
String CSSMutableStyleDeclaration::getPropertyValue(int propertyID) const
{
    RefPtr<CSSValue> value = getPropertyCSSValue(propertyID);
    if (value)
        return value->cssText();

    // Shorthand and 4-values properties
    switch (propertyID) {
        case CSSPropertyBackgroundPosition: {
            // FIXME: Is this correct? The code in cssparser.cpp is confusing
            const int properties[2] = { CSSPropertyBackgroundPositionX,
                                        CSSPropertyBackgroundPositionY };
            return getLayeredShorthandValue(properties, 2);
        }
        case CSSPropertyBackground: {
            const int properties[7] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundRepeat, 
                                        CSSPropertyBackgroundAttachment, CSSPropertyBackgroundPosition, CSSPropertyWebkitBackgroundClip,
                                        CSSPropertyWebkitBackgroundOrigin, CSSPropertyBackgroundColor };
            return getLayeredShorthandValue(properties, 7);
        }
        case CSSPropertyBorder: {
            const int properties[3][4] = {{ CSSPropertyBorderTopWidth,
                                            CSSPropertyBorderRightWidth,
                                            CSSPropertyBorderBottomWidth,
                                            CSSPropertyBorderLeftWidth },
                                          { CSSPropertyBorderTopStyle,
                                            CSSPropertyBorderRightStyle,
                                            CSSPropertyBorderBottomStyle,
                                            CSSPropertyBorderLeftStyle },
                                          { CSSPropertyBorderTopColor,
                                            CSSPropertyBorderRightColor,
                                            CSSPropertyBorderBottomColor,
                                            CSSPropertyBorderLeftColor }};
            String res;
            const int nrprops = sizeof(properties) / sizeof(properties[0]);
            for (int i = 0; i < nrprops; ++i) {
                String value = getCommonValue(properties[i], 4);
                if (!value.isNull()) {
                    if (!res.isNull())
                        res += " ";
                    res += value;
                }
            }
            return res;
        }
        case CSSPropertyBorderTop: {
            const int properties[3] = { CSSPropertyBorderTopWidth, CSSPropertyBorderTopStyle,
                                        CSSPropertyBorderTopColor};
            return getShorthandValue(properties, 3);
        }
        case CSSPropertyBorderRight: {
            const int properties[3] = { CSSPropertyBorderRightWidth, CSSPropertyBorderRightStyle,
                                        CSSPropertyBorderRightColor};
            return getShorthandValue(properties, 3);
        }
        case CSSPropertyBorderBottom: {
            const int properties[3] = { CSSPropertyBorderBottomWidth, CSSPropertyBorderBottomStyle,
                                        CSSPropertyBorderBottomColor};
            return getShorthandValue(properties, 3);
        }
        case CSSPropertyBorderLeft: {
            const int properties[3] = { CSSPropertyBorderLeftWidth, CSSPropertyBorderLeftStyle,
                                        CSSPropertyBorderLeftColor};
            return getShorthandValue(properties, 3);
        }
        case CSSPropertyOutline: {
            const int properties[3] = { CSSPropertyOutlineWidth, CSSPropertyOutlineStyle,
                                        CSSPropertyOutlineColor };
            return getShorthandValue(properties, 3);
        }
        case CSSPropertyBorderColor: {
            const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor,
                                        CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor };
            return get4Values(properties);
        }
        case CSSPropertyBorderWidth: {
            const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth,
                                        CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth };
            return get4Values(properties);
        }
        case CSSPropertyBorderStyle: {
            const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle,
                                        CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle };
            return get4Values(properties);
        }
        case CSSPropertyMargin: {
            const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight,
                                        CSSPropertyMarginBottom, CSSPropertyMarginLeft };
            return get4Values(properties);
        }
        case CSSPropertyPadding: {
            const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight,
                                        CSSPropertyPaddingBottom, CSSPropertyPaddingLeft };
            return get4Values(properties);
        }
        case CSSPropertyListStyle: {
            const int properties[3] = { CSSPropertyListStyleType, CSSPropertyListStylePosition,
                                        CSSPropertyListStyleImage };
            return getShorthandValue(properties, 3);
        }
        case CSSPropertyWebkitMaskPosition: {
            // FIXME: Is this correct? The code in cssparser.cpp is confusing
            const int properties[2] = { CSSPropertyWebkitMaskPositionX,
                                        CSSPropertyWebkitMaskPositionY };
            return getLayeredShorthandValue(properties, 2);
        }
        case CSSPropertyWebkitMask: {
            const int properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat, 
                                       CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskClip,
                                       CSSPropertyWebkitMaskOrigin };
            return getLayeredShorthandValue(properties, 6);
        }
#if ENABLE(SVG)
        case CSSPropertyMarker: {
            RefPtr<CSSValue> value = getPropertyCSSValue(CSSPropertyMarkerStart);
            if (value)
                return value->cssText();
        }
#endif
    }
    return String();
}
static IntlCollator* initializeCollator(ExecState& state, IntlCollator& collator, JSValue locales, JSValue optionsValue)
{
    // 10.1.1 InitializeCollator (collator, locales, options) (ECMA-402 2.0)

    // 1. If collator has an [[initializedIntlObject]] internal slot with value true, throw a TypeError exception.
    // 2. Set collator.[[initializedIntlObject]] to true.

    // 3. Let requestedLocales be CanonicalizeLocaleList(locales).
    Vector<String> requestedLocales = canonicalizeLocaleList(state, locales);
    // 4. ReturnIfAbrupt(requestedLocales).
    if (state.hadException())
        return nullptr;

    // 5. If options is undefined, then
    JSObject* options;
    if (optionsValue.isUndefined()) {
        // a. Let options be ObjectCreate(%ObjectPrototype%).
        options = constructEmptyObject(&state);
    } else { // 6. Else
        // a. Let options be ToObject(options).
        options = optionsValue.toObject(&state);
        // b. ReturnIfAbrupt(options).
        if (state.hadException())
            return nullptr;
    }

    // 7. Let u be GetOption(options, "usage", "string", «"sort", "search"», "sort").
    const HashSet<String> usages({ ASCIILiteral("sort"), ASCIILiteral("search") });
    String usage = intlStringOption(state, options, state.vm().propertyNames->usage, usages, "usage must be either \"sort\" or \"search\"", ASCIILiteral("sort"));
    // 8. ReturnIfAbrupt(u).
    if (state.hadException())
        return nullptr;
    // 9. Set collator.[[usage]] to u.
    collator.setUsage(usage);

    // 10. If u is "sort", then
    // a. Let localeData be the value of %Collator%.[[sortLocaleData]];
    // 11. Else
    // a. Let localeData be the value of %Collator%.[[searchLocaleData]].
    Vector<String> (*localeData)(const String&, const String&);
    if (usage == "sort")
        localeData = sortLocaleData;
    else
        localeData = searchLocaleData;

    // 12. Let opt be a new Record.
    HashMap<String, String> opt;

    // 13. Let matcher be GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit").
    const HashSet<String> matchers({ ASCIILiteral("lookup"), ASCIILiteral("best fit") });
    String matcher = intlStringOption(state, options, state.vm().propertyNames->localeMatcher, matchers, "localeMatcher must be either \"lookup\" or \"best fit\"", ASCIILiteral("best fit"));
    // 14. ReturnIfAbrupt(matcher).
    if (state.hadException())
        return nullptr;
    // 15. Set opt.[[localeMatcher]] to matcher.
    opt.set(ASCIILiteral("localeMatcher"), matcher);

    // 16. For each row in Table 1, except the header row, do:
    // a. Let key be the name given in the Key column of the row.
    // b. Let prop be the name given in the Property column of the row.
    // c. Let type be the string given in the Type column of the row.
    // d. Let list be a List containing the Strings given in the Values column of the row, or undefined if no strings are given.
    // e. Let value be GetOption(options, prop, type, list, undefined).
    // f. ReturnIfAbrupt(value).
    // g. If the string given in the Type column of the row is "boolean" and value is not undefined, then
    //    i. Let value be ToString(value).
    //    ii. ReturnIfAbrupt(value).
    // h. Set opt.[[<key>]] to value.
    {
        String numericString;
        bool usesFallback;
        bool numeric = intlBooleanOption(state, options, state.vm().propertyNames->numeric, usesFallback);
        if (state.hadException())
            return nullptr;
        if (!usesFallback)
            numericString = ASCIILiteral(numeric ? "true" : "false");
        opt.set(ASCIILiteral("kn"), numericString);
    }
    {
        const HashSet<String> caseFirsts({ ASCIILiteral("upper"), ASCIILiteral("lower"), ASCIILiteral("false") });
        String caseFirst = intlStringOption(state, options, state.vm().propertyNames->caseFirst, caseFirsts, "caseFirst must be either \"upper\", \"lower\", or \"false\"", String());
        if (state.hadException())
            return nullptr;
        opt.set(ASCIILiteral("kf"), caseFirst);
    }

    // 17. Let relevantExtensionKeys be the value of %Collator%.[[relevantExtensionKeys]].
    // FIXME: Implement kf (caseFirst).
    const Vector<String> relevantExtensionKeys { ASCIILiteral("co"), ASCIILiteral("kn") };

    // 18. Let r be ResolveLocale(%Collator%.[[availableLocales]], requestedLocales, opt, relevantExtensionKeys, localeData).
    const HashSet<String>& availableLocales = state.callee()->globalObject()->intlCollatorAvailableLocales();
    HashMap<String, String> result = resolveLocale(availableLocales, requestedLocales, opt, relevantExtensionKeys, localeData);

    // 19. Set collator.[[locale]] to the value of r.[[locale]].
    collator.setLocale(result.get(ASCIILiteral("locale")));

    // 20. Let k be 0.
    // 21. Let lenValue be Get(relevantExtensionKeys, "length").
    // 22. Let len be ToLength(lenValue).
    // 23. Repeat while k < len:
    // a. Let Pk be ToString(k).
    // b. Let key be Get(relevantExtensionKeys, Pk).
    // c. ReturnIfAbrupt(key).
    // d. If key is "co", then
    //    i. Let property be "collation".
    //    ii. Let value be the value of r.[[co]].
    //    iii. If value is null, let value be "default".
    // e. Else use the row of Table 1 that contains the value of key in the Key column:
    //    i. Let property be the name given in the Property column of the row.
    //    ii. Let value be the value of r.[[<key>]].
    //    iii. If the name given in the Type column of the row is "boolean", let value be the result of comparing value with "true".
    // f. Set collator.[[<property>]] to value.
    // g. Increase k by 1.
    ASSERT(relevantExtensionKeys.size() == 2);
    {
        ASSERT(relevantExtensionKeys[0] == "co");
        const String& value = result.get(ASCIILiteral("co"));
        collator.setCollation(value.isNull() ? ASCIILiteral("default") : value);
    }
    {
        ASSERT(relevantExtensionKeys[1] == "kn");
        const String& value = result.get(ASCIILiteral("kn"));
        collator.setNumeric(value == "true");
    }

    // 24. Let s be GetOption(options, "sensitivity", "string", «"base", "accent", "case", "variant"», undefined).
    const HashSet<String> sensitivities({ ASCIILiteral("base"), ASCIILiteral("accent"), ASCIILiteral("case"), ASCIILiteral("variant") });
    String sensitivity = intlStringOption(state, options, state.vm().propertyNames->sensitivity, sensitivities, "sensitivity must be either \"base\", \"accent\", \"case\", or \"variant\"", String());
    // 25. ReturnIfAbrupt(s).
    if (state.hadException())
        return nullptr;
    // 26. If s is undefined, then
    if (sensitivity.isNull()) {
        // a. If u is "sort", then let s be "variant".
        if (usage == "sort")
            sensitivity = ASCIILiteral("variant");
        else {
            // b. Else
            //    i. Let dataLocale be the value of r.[[dataLocale]].
            //    ii. Let dataLocaleData be Get(localeData, dataLocale).
            //    iii. Let s be Get(dataLocaleData, "sensitivity").
            const String& dataLocale = result.get(ASCIILiteral("dataLocale"));
            sensitivity = localeData(dataLocale, ASCIILiteral("sensitivity"))[0];
        }
    }
    // 27. Set collator.[[sensitivity]] to s.
    collator.setSensitivity(sensitivity);

    // 28. Let ip be GetOption(options, "ignorePunctuation", "boolean", undefined, false).
    bool usesFallback;
    bool ignorePunctuation = intlBooleanOption(state, options, state.vm().propertyNames->ignorePunctuation, usesFallback);
    if (usesFallback)
        ignorePunctuation = false;
    // 29. ReturnIfAbrupt(ip).
    if (state.hadException())
        return nullptr;
    // 30. Set collator.[[ignorePunctuation]] to ip.
    collator.setIgnorePunctuation(ignorePunctuation);

    // 31. Set collator.[[boundCompare]] to undefined.
    // 32. Set collator.[[initializedCollator]] to true.
    // 33. Return collator.
    return &collator;
}
Example #19
0
JSValuePtr jsStringOrFalse(ExecState* exec, const String& s)
{
    if (s.isNull())
        return jsBoolean(false);
    return jsString(exec, s);
}
Example #20
0
void XSSAuditor::init(Document* document, XSSAuditorDelegate* auditorDelegate)
{
    const size_t minimumLengthForSuffixTree = 512; // FIXME: Tune this parameter.
    const int suffixTreeDepth = 5;

    ASSERT(isMainThread());
    if (m_state == Initialized)
        return;
    ASSERT(m_state == Uninitialized);
    m_state = Initialized;

    if (Frame* frame = document->frame())
        m_isEnabled = frame->settings().xssAuditorEnabled();

    if (!m_isEnabled)
        return;

    m_documentURL = document->url().isolatedCopy();

    // In theory, the Document could have detached from the Frame after the
    // XSSAuditor was constructed.
    if (!document->frame()) {
        m_isEnabled = false;
        return;
    }

    if (m_documentURL.isEmpty()) {
        // The URL can be empty when opening a new browser window or calling window.open("").
        m_isEnabled = false;
        return;
    }

    if (m_documentURL.protocolIsData()) {
        m_isEnabled = false;
        return;
    }

    if (document->decoder())
        m_encoding = document->decoder()->encoding();

    m_decodedURL = canonicalize(m_documentURL.string(), TruncationStyle::None);
    if (m_decodedURL.find(isRequiredForInjection) == notFound)
        m_decodedURL = String();

    String httpBodyAsString;
    if (DocumentLoader* documentLoader = document->frame()->loader().documentLoader()) {
        static NeverDestroyed<String> XSSProtectionHeader(ASCIILiteral("X-XSS-Protection"));
        String headerValue = documentLoader->response().httpHeaderField(XSSProtectionHeader);
        String errorDetails;
        unsigned errorPosition = 0;
        String parsedReportURL;
        URL reportURL;
        m_xssProtection = parseXSSProtectionHeader(headerValue, errorDetails, errorPosition, parsedReportURL);
        m_didSendValidXSSProtectionHeader = !headerValue.isNull() && m_xssProtection != XSSProtectionDisposition::Invalid;

        if ((m_xssProtection == XSSProtectionDisposition::Enabled || m_xssProtection == XSSProtectionDisposition::BlockEnabled) && !parsedReportURL.isEmpty()) {
            reportURL = document->completeURL(parsedReportURL);
            if (MixedContentChecker::isMixedContent(document->securityOrigin(), reportURL)) {
                errorDetails = "insecure reporting URL for secure page";
                m_xssProtection = XSSProtectionDisposition::Invalid;
                reportURL = URL();
                m_didSendValidXSSProtectionHeader = false;
            }
        }
        if (m_xssProtection == XSSProtectionDisposition::Invalid) {
            document->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Error parsing header X-XSS-Protection: " + headerValue + ": "  + errorDetails + " at character position " + String::format("%u", errorPosition) + ". The default protections will be applied.");
            m_xssProtection = XSSProtectionDisposition::Enabled;
        }

        if (auditorDelegate)
            auditorDelegate->setReportURL(reportURL.isolatedCopy());
        FormData* httpBody = documentLoader->originalRequest().httpBody();
        if (httpBody && !httpBody->isEmpty()) {
            httpBodyAsString = httpBody->flattenToString();
            if (!httpBodyAsString.isEmpty()) {
                m_decodedHTTPBody = canonicalize(httpBodyAsString, TruncationStyle::None);
                if (m_decodedHTTPBody.find(isRequiredForInjection) == notFound)
                    m_decodedHTTPBody = String();
                if (m_decodedHTTPBody.length() >= minimumLengthForSuffixTree)
                    m_decodedHTTPBodySuffixTree = std::make_unique<SuffixTree<ASCIICodebook>>(m_decodedHTTPBody, suffixTreeDepth);
            }
        }
    }

    if (m_decodedURL.isEmpty() && m_decodedHTTPBody.isEmpty()) {
        m_isEnabled = false;
        return;
    }
}
Example #21
0
void IntlDateTimeFormat::initializeDateTimeFormat(ExecState& exec, JSValue locales, JSValue originalOptions)
{
    VM& vm = exec.vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    // 12.1.1 InitializeDateTimeFormat (dateTimeFormat, locales, options) (ECMA-402 2.0)
    // 1. If dateTimeFormat.[[initializedIntlObject]] is true, throw a TypeError exception.
    // 2. Set dateTimeFormat.[[initializedIntlObject]] to true.

    // 3. Let requestedLocales be CanonicalizeLocaleList(locales).
    Vector<String> requestedLocales = canonicalizeLocaleList(exec, locales);
    // 4. ReturnIfAbrupt(requestedLocales),
    RETURN_IF_EXCEPTION(scope, void());

    // 5. Let options be ToDateTimeOptions(options, "any", "date").
    JSObject* options = toDateTimeOptionsAnyDate(exec, originalOptions);
    // 6. ReturnIfAbrupt(options).
    RETURN_IF_EXCEPTION(scope, void());

    // 7. Let opt be a new Record.
    HashMap<String, String> localeOpt;

    // 8. Let matcher be GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit").
    String localeMatcher = intlStringOption(exec, options, vm.propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit");
    // 9. ReturnIfAbrupt(matcher).
    RETURN_IF_EXCEPTION(scope, void());
    // 10. Set opt.[[localeMatcher]] to matcher.
    localeOpt.add(vm.propertyNames->localeMatcher.string(), localeMatcher);

    // 11. Let localeData be the value of %DateTimeFormat%.[[localeData]].
    // 12. Let r be ResolveLocale( %DateTimeFormat%.[[availableLocales]], requestedLocales, opt, %DateTimeFormat%.[[relevantExtensionKeys]], localeData).
    const HashSet<String> availableLocales = exec.callee()->globalObject()->intlDateTimeFormatAvailableLocales();
    HashMap<String, String> resolved = resolveLocale(exec, availableLocales, requestedLocales, localeOpt, relevantExtensionKeys, WTF_ARRAY_LENGTH(relevantExtensionKeys), localeData);

    // 13. Set dateTimeFormat.[[locale]] to the value of r.[[locale]].
    m_locale = resolved.get(vm.propertyNames->locale.string());
    if (m_locale.isEmpty()) {
        throwTypeError(&exec, scope, ASCIILiteral("failed to initialize DateTimeFormat due to invalid locale"));
        return;
    }
    // 14. Set dateTimeFormat.[[calendar]] to the value of r.[[ca]].
    m_calendar = resolved.get(ASCIILiteral("ca"));
    // Switch to preferred aliases.
    if (m_calendar == "gregory")
        m_calendar = ASCIILiteral("gregorian");
    else if (m_calendar == "islamicc")
        m_calendar = ASCIILiteral("islamic-civil");
    else if (m_calendar == "ethioaa")
        m_calendar = ASCIILiteral("ethiopic-amete-alem");
    // 15. Set dateTimeFormat.[[numberingSystem]] to the value of r.[[nu]].
    m_numberingSystem = resolved.get(ASCIILiteral("nu"));
    // 16. Let dataLocale be the value of r.[[dataLocale]].
    String dataLocale = resolved.get(ASCIILiteral("dataLocale"));

    // 17. Let tz be Get(options, "timeZone").
    JSValue tzValue = options->get(&exec, vm.propertyNames->timeZone);
    // 18. ReturnIfAbrupt(tz).
    RETURN_IF_EXCEPTION(scope, void());

    // 19. If tz is not undefined, then
    String tz;
    if (!tzValue.isUndefined()) {
        // a. Let tz be ToString(tz).
        String originalTz = tzValue.toWTFString(&exec);
        // b. ReturnIfAbrupt(tz).
        RETURN_IF_EXCEPTION(scope, void());
        // c. If the result of IsValidTimeZoneName(tz) is false, then i. Throw a RangeError exception.
        // d. Let tz be CanonicalizeTimeZoneName(tz).
        tz = canonicalizeTimeZoneName(originalTz);
        if (tz.isNull()) {
            throwRangeError(&exec, scope, String::format("invalid time zone: %s", originalTz.utf8().data()));
            return;
        }
    } else {
        // 20. Else,
        // a. Let tz be DefaultTimeZone().
        tz = defaultTimeZone();
    }

    // 21. Set dateTimeFormat.[[timeZone]] to tz.
    m_timeZone = tz;

    // 22. Let opt be a new Record.
    // Rather than building a record, build the skeleton pattern.
    StringBuilder skeletonBuilder;

    // 23. For each row of Table 3, except the header row, do:
    // a. Let prop be the name given in the Property column of the row.
    // b. Let value be GetOption(options, prop, "string", «the strings given in the Values column of the row», undefined).
    // c. ReturnIfAbrupt(value).
    // d. Set opt.[[<prop>]] to value.
    auto narrowShortLong = { "narrow", "short", "long" };
    auto twoDigitNumeric = { "2-digit", "numeric" };
    auto twoDigitNumericNarrowShortLong = { "2-digit", "numeric", "narrow", "short", "long" };
    auto shortLong = { "short", "long" };

    String weekday = intlStringOption(exec, options, vm.propertyNames->weekday, narrowShortLong, "weekday must be \"narrow\", \"short\", or \"long\"", nullptr);
    RETURN_IF_EXCEPTION(scope, void());
    if (!weekday.isNull()) {
        if (weekday == "narrow")
            skeletonBuilder.appendLiteral("EEEEE");
        else if (weekday == "short")
            skeletonBuilder.appendLiteral("EEE");
        else if (weekday == "long")
            skeletonBuilder.appendLiteral("EEEE");
    }

    String era = intlStringOption(exec, options, vm.propertyNames->era, narrowShortLong, "era must be \"narrow\", \"short\", or \"long\"", nullptr);
    RETURN_IF_EXCEPTION(scope, void());
    if (!era.isNull()) {
        if (era == "narrow")
            skeletonBuilder.appendLiteral("GGGGG");
        else if (era == "short")
            skeletonBuilder.appendLiteral("GGG");
        else if (era == "long")
            skeletonBuilder.appendLiteral("GGGG");
    }

    String year = intlStringOption(exec, options, vm.propertyNames->year, twoDigitNumeric, "year must be \"2-digit\" or \"numeric\"", nullptr);
    RETURN_IF_EXCEPTION(scope, void());
    if (!year.isNull()) {
        if (year == "2-digit")
            skeletonBuilder.appendLiteral("yy");
        else if (year == "numeric")
            skeletonBuilder.append('y');
    }

    String month = intlStringOption(exec, options, vm.propertyNames->month, twoDigitNumericNarrowShortLong, "month must be \"2-digit\", \"numeric\", \"narrow\", \"short\", or \"long\"", nullptr);
    RETURN_IF_EXCEPTION(scope, void());
    if (!month.isNull()) {
        if (month == "2-digit")
            skeletonBuilder.appendLiteral("MM");
        else if (month == "numeric")
            skeletonBuilder.append('M');
        else if (month == "narrow")
            skeletonBuilder.appendLiteral("MMMMM");
        else if (month == "short")
            skeletonBuilder.appendLiteral("MMM");
        else if (month == "long")
            skeletonBuilder.appendLiteral("MMMM");
    }

    String day = intlStringOption(exec, options, vm.propertyNames->day, twoDigitNumeric, "day must be \"2-digit\" or \"numeric\"", nullptr);
    RETURN_IF_EXCEPTION(scope, void());
    if (!day.isNull()) {
        if (day == "2-digit")
            skeletonBuilder.appendLiteral("dd");
        else if (day == "numeric")
            skeletonBuilder.append('d');
    }

    String hour = intlStringOption(exec, options, vm.propertyNames->hour, twoDigitNumeric, "hour must be \"2-digit\" or \"numeric\"", nullptr);
    RETURN_IF_EXCEPTION(scope, void());

    // We need hour12 to make the hour skeleton pattern decision, so do this early.
    // 32. Let hr12 be GetOption(options, "hour12", "boolean", undefined, undefined).
    bool isHour12Undefined;
    bool hr12 = intlBooleanOption(exec, options, vm.propertyNames->hour12, isHour12Undefined);
    // 33. ReturnIfAbrupt(hr12).
    RETURN_IF_EXCEPTION(scope, void());

    if (!hour.isNull()) {
        if (isHour12Undefined) {
            if (hour == "2-digit")
                skeletonBuilder.appendLiteral("jj");
            else if (hour == "numeric")
                skeletonBuilder.append('j');
        } else if (hr12) {
            if (hour == "2-digit")
                skeletonBuilder.appendLiteral("hh");
            else if (hour == "numeric")
                skeletonBuilder.append('h');
        } else {
            if (hour == "2-digit")
                skeletonBuilder.appendLiteral("HH");
            else if (hour == "numeric")
                skeletonBuilder.append('H');
        }
    }

    String minute = intlStringOption(exec, options, vm.propertyNames->minute, twoDigitNumeric, "minute must be \"2-digit\" or \"numeric\"", nullptr);
    RETURN_IF_EXCEPTION(scope, void());
    if (!minute.isNull()) {
        if (minute == "2-digit")
            skeletonBuilder.appendLiteral("mm");
        else if (minute == "numeric")
            skeletonBuilder.append('m');
    }

    String second = intlStringOption(exec, options, vm.propertyNames->second, twoDigitNumeric, "second must be \"2-digit\" or \"numeric\"", nullptr);
    RETURN_IF_EXCEPTION(scope, void());
    if (!second.isNull()) {
        if (second == "2-digit")
            skeletonBuilder.appendLiteral("ss");
        else if (second == "numeric")
            skeletonBuilder.append('s');
    }

    String timeZoneName = intlStringOption(exec, options, vm.propertyNames->timeZoneName, shortLong, "timeZoneName must be \"short\" or \"long\"", nullptr);
    RETURN_IF_EXCEPTION(scope, void());
    if (!timeZoneName.isNull()) {
        if (timeZoneName == "short")
            skeletonBuilder.append('z');
        else if (timeZoneName == "long")
            skeletonBuilder.appendLiteral("zzzz");
    }

    // 24. Let dataLocaleData be Get(localeData, dataLocale).
    // 25. Let formats be Get(dataLocaleData, "formats").
    // 26. Let matcher be GetOption(options, "formatMatcher", "string", «"basic", "best fit"», "best fit").
    intlStringOption(exec, options, vm.propertyNames->formatMatcher, { "basic", "best fit" }, "formatMatcher must be either \"basic\" or \"best fit\"", "best fit");
    // 27. ReturnIfAbrupt(matcher).
    RETURN_IF_EXCEPTION(scope, void());

    // Always use ICU date format generator, rather than our own pattern list and matcher.
    // Covers steps 28-36.
    UErrorCode status = U_ZERO_ERROR;
    UDateTimePatternGenerator* generator = udatpg_open(dataLocale.utf8().data(), &status);
    if (U_FAILURE(status)) {
        throwTypeError(&exec, scope, ASCIILiteral("failed to initialize DateTimeFormat"));
        return;
    }

    String skeleton = skeletonBuilder.toString();
    StringView skeletonView(skeleton);
    Vector<UChar, 32> patternBuffer(32);
    status = U_ZERO_ERROR;
    auto patternLength = udatpg_getBestPattern(generator, skeletonView.upconvertedCharacters(), skeletonView.length(), patternBuffer.data(), patternBuffer.size(), &status);
    if (status == U_BUFFER_OVERFLOW_ERROR) {
        status = U_ZERO_ERROR;
        patternBuffer.grow(patternLength);
        udatpg_getBestPattern(generator, skeletonView.upconvertedCharacters(), skeletonView.length(), patternBuffer.data(), patternLength, &status);
    }
    udatpg_close(generator);
    if (U_FAILURE(status)) {
        throwTypeError(&exec, scope, ASCIILiteral("failed to initialize DateTimeFormat"));
        return;
    }

    StringView pattern(patternBuffer.data(), patternLength);
    setFormatsFromPattern(pattern);

    status = U_ZERO_ERROR;
    StringView timeZoneView(m_timeZone);
    m_dateFormat = std::unique_ptr<UDateFormat, UDateFormatDeleter>(udat_open(UDAT_PATTERN, UDAT_PATTERN, m_locale.utf8().data(), timeZoneView.upconvertedCharacters(), timeZoneView.length(), pattern.upconvertedCharacters(), pattern.length(), &status));
    if (U_FAILURE(status)) {
        throwTypeError(&exec, scope, ASCIILiteral("failed to initialize DateTimeFormat"));
        return;
    }

    // 37. Set dateTimeFormat.[[boundFormat]] to undefined.
    // Already undefined.

    // 38. Set dateTimeFormat.[[initializedDateTimeFormat]] to true.
    m_initializedDateTimeFormat = true;

    // 39. Return dateTimeFormat.
}
Example #22
0
void WebVTTParser::parse()
{    
    // WebVTT parser algorithm. (5.1 WebVTT file parsing.)
    // Steps 1 - 3 - Initial setup.
    String line;
    while (m_lineReader.getLine(line)) {
        if (line.isNull())
            return;

        switch (m_state) {
        case Initial:
            // Steps 4 - 9 - Check for a valid WebVTT signature.
            if (!hasRequiredFileIdentifier(line)) {
                if (m_client)
                    m_client->fileFailedToParse();
                return;
            }

            m_state = Header;
            break;

        case Header:
            collectMetadataHeader(line);

            if (line.isEmpty()) {
#if ENABLE(WEBVTT_REGIONS)
                // Steps 10-14 - Allow a header (comment area) under the WEBVTT line.
                if (m_client && m_regionList.size())
                    m_client->newRegionsParsed();
#endif
                m_state = Id;
                break;
            }
            // Step 15 - Break out of header loop if the line could be a timestamp line.
            if (line.contains("-->"))
                m_state = recoverCue(line);

            // Step 16 - Line is not the empty string and does not contain "-->".
            break;

        case Id:
            // Steps 17 - 20 - Allow any number of line terminators, then initialize new cue values.
            if (line.isEmpty())
                break;

            // Step 21 - Cue creation (start a new cue).
            resetCueValues();

            // Steps 22 - 25 - Check if this line contains an optional identifier or timing data.
            m_state = collectCueId(line);
            break;

        case TimingsAndSettings:
            // Steps 26 - 27 - Discard current cue if the line is empty.
            if (line.isEmpty()) {
                m_state = Id;
                break;
            }

            // Steps 28 - 29 - Collect cue timings and settings.
            m_state = collectTimingsAndSettings(line);
            break;

        case CueText:
            // Steps 31 - 41 - Collect the cue text, create a cue, and add it to the output.
            m_state = collectCueText(line);
            break;

        case BadCue:
            // Steps 42 - 48 - Discard lines until an empty line or a potential timing line is seen.
            m_state = ignoreBadCue(line);
            break;

        case Finished:
            ASSERT_NOT_REACHED();
            break;
        }
    }
}
Example #23
0
v8::Handle<v8::Value> v8StringOrFalse(const String& str)
{
    return str.isNull() ? v8::Handle<v8::Value>(v8::False()) : v8::Handle<v8::Value>(v8String(str));
}
Example #24
0
void ResourceRequest::doUpdatePlatformRequest()
{
    CFMutableURLRequestRef cfRequest;

    RetainPtr<CFURLRef> url = ResourceRequest::url().createCFURL();
    RetainPtr<CFURLRef> firstPartyForCookies = ResourceRequest::firstPartyForCookies().createCFURL();
    if (m_cfRequest) {
        cfRequest = CFURLRequestCreateMutableCopy(0, m_cfRequest.get());
        CFURLRequestSetURL(cfRequest, url.get());
        CFURLRequestSetMainDocumentURL(cfRequest, firstPartyForCookies.get());
        CFURLRequestSetCachePolicy(cfRequest, (CFURLRequestCachePolicy)cachePolicy());
        CFURLRequestSetTimeoutInterval(cfRequest, timeoutInterval());
    } else
        cfRequest = CFURLRequestCreateMutable(0, url.get(), (CFURLRequestCachePolicy)cachePolicy(), timeoutInterval(), firstPartyForCookies.get());

    CFURLRequestSetHTTPRequestMethod(cfRequest, httpMethod().createCFString().get());

    if (httpPipeliningEnabled())
        wkHTTPRequestEnablePipelining(cfRequest);

    if (resourcePrioritiesEnabled())
        wkSetHTTPRequestPriority(cfRequest, toPlatformRequestPriority(m_priority));

#if !PLATFORM(WIN)
    wkCFURLRequestAllowAllPostCaching(cfRequest);
#endif

    setHeaderFields(cfRequest, httpHeaderFields());

    CFURLRequestSetShouldHandleHTTPCookies(cfRequest, allowCookies());

    unsigned fallbackCount = m_responseContentDispositionEncodingFallbackArray.size();
    RetainPtr<CFMutableArrayRef> encodingFallbacks = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, fallbackCount, 0));
    for (unsigned i = 0; i != fallbackCount; ++i) {
        RetainPtr<CFStringRef> encodingName = m_responseContentDispositionEncodingFallbackArray[i].createCFString();
        CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding(encodingName.get());
        if (encoding != kCFStringEncodingInvalidId)
            CFArrayAppendValue(encodingFallbacks.get(), reinterpret_cast<const void*>(encoding));
    }
    setContentDispositionEncodingFallbackArray(cfRequest, encodingFallbacks.get());

    if (m_cfRequest) {
        RetainPtr<CFHTTPCookieStorageRef> cookieStorage = adoptCF(CFURLRequestCopyHTTPCookieStorage(m_cfRequest.get()));
        if (cookieStorage)
            CFURLRequestSetHTTPCookieStorage(cfRequest, cookieStorage.get());
        CFURLRequestSetHTTPCookieStorageAcceptPolicy(cfRequest, CFURLRequestGetHTTPCookieStorageAcceptPolicy(m_cfRequest.get()));
        CFURLRequestSetSSLProperties(cfRequest, CFURLRequestGetSSLProperties(m_cfRequest.get()));
    }

#if ENABLE(CACHE_PARTITIONING)
    String partition = cachePartition();
    if (!partition.isNull() && !partition.isEmpty()) {
        CString utf8String = partition.utf8();
        RetainPtr<CFStringRef> partitionValue = adoptCF(CFStringCreateWithBytes(0, reinterpret_cast<const UInt8*>(utf8String.data()), utf8String.length(), kCFStringEncodingUTF8, false));
        _CFURLRequestSetProtocolProperty(cfRequest, wkCachePartitionKey(), partitionValue.get());
    }
#endif

    m_cfRequest = adoptCF(cfRequest);
#if PLATFORM(COCOA)
    clearOrUpdateNSURLRequest();
#endif
}
Example #25
0
Variant HHVM_FUNCTION(readline_info, const String& varname /* = null */,
                                     const String& newvalue /* = null */) {
  if (varname.isNull()) {
    ArrayInit ret(12, ArrayInit::Map{});
    ret.add(s_line_buffer, convert_null_to_empty(rl_line_buffer));
    ret.add(s_point, rl_point);
    ret.add(s_end, rl_end);
#ifndef USE_EDITLINE
    ret.add(s_mark, rl_mark);
    ret.add(s_done, rl_done);
    ret.add(s_pending_input, rl_pending_input);
    ret.add(s_prompt, convert_null_to_empty(rl_prompt));
    ret.add(s_terminal_name, convert_null_to_empty(rl_terminal_name));
#endif
#if HAVE_ERASE_EMPTY_LINE
    ret.add(s_erase_empty_line, rl_erase_empty_line);
#endif
    ret.add(s_library_version, convert_null_to_empty(rl_library_version));
    ret.add(s_readline_name, convert_null_to_empty(rl_readline_name));
    ret.add(s_attempted_completion_over, rl_attempted_completion_over);
    return ret.toArray();
  } else {
    Variant oldval;
    if (varname == s_line_buffer) {
      oldval = String(convert_null_to_empty(rl_line_buffer));
      if (!newvalue.isNull() && oldval.toString() != newvalue) {
        Lock lock(info_lock);
        raise_warning(
          "This probably isn't doing what you expect it to do, " \
          "this buffer is set for EVERY request."
        );
        free(_rl_line_buffer);
        _rl_line_buffer = strdup(newvalue.data());
        rl_line_buffer = _rl_line_buffer;
      }
      return oldval;
    } else if (varname == s_point) {
      return rl_point;
    } else if (varname == s_end) {
      return rl_end;
#ifndef USE_EDITLINE
    } else if (varname == s_mark) {
      return rl_mark;
    } else if (varname == s_done) {
      oldval = rl_done;
      if (!newvalue.isNull()) {
        rl_done = newvalue.toInt64();
      }
      return oldval;
    } else if (varname == s_pending_input) {
      oldval = rl_pending_input;
      if (!newvalue.isNull()) {
        rl_pending_input = newvalue.toInt64();
      }
      return oldval;
    } else if (varname == s_prompt) {
      return convert_null_to_empty(rl_prompt);
#endif
#if HAVE_ERASE_EMPTY_LINE
    } else if (varname == s_erase_empty_line) {
      oldval = rl_erase_empty_line;
      if (!newvalue.isNull()) {
        rl_erase_empty_line = newvalue.toInt64();
      }
      return oldval;
#endif
    } else if (varname == s_library_version) {
      return convert_null_to_empty(rl_library_version);
    } else if (varname == s_readline_name) {
      oldval = String(convert_null_to_empty(rl_readline_name));
      if (!newvalue.isNull() && oldval.toString() != newvalue) {
        Lock lock(info_lock);
        raise_warning(
          "This probably isn't doing what you expect it to do, " \
          "this name is set for EVERY request."
        );
        free(_rl_readline_name);
        _rl_readline_name = strdup(newvalue.data());
        rl_readline_name = _rl_readline_name;
      }
      return oldval;
    } else if (varname == s_attempted_completion_over) {
      oldval = rl_attempted_completion_over;
      if (!newvalue.isNull()) {
        rl_attempted_completion_over = newvalue.toInt64();
      }
      return oldval;
    }
  }
  return null_variant;
}
bool DatabaseBackendBase::performOpenAndVerify(bool shouldSetVersionInNewDatabase, DatabaseError& error, String& errorMessage)
{
    DoneCreatingDatabaseOnExitCaller onExitCaller(this);
    ASSERT(errorMessage.isEmpty());
    ASSERT(error == DatabaseError::None); // Better not have any errors already.
    error = DatabaseError::InvalidDatabaseState; // Presumed failure. We'll clear it if we succeed below.

    const int maxSqliteBusyWaitTime = 30000;

    if (!m_sqliteDatabase.open(m_filename, true)) {
        reportOpenDatabaseResult(1, InvalidStateError, m_sqliteDatabase.lastError());
        errorMessage = formatErrorMessage("unable to open database", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
        return false;
    }
    if (!m_sqliteDatabase.turnOnIncrementalAutoVacuum())
        LOG_ERROR("Unable to turn on incremental auto-vacuum (%d %s)", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());

    m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime);

    String currentVersion;
    {
        MutexLocker locker(guidMutex());

        GuidVersionMap::iterator entry = guidToVersionMap().find(m_guid);
        if (entry != guidToVersionMap().end()) {
            // Map null string to empty string (see updateGuidVersionMap()).
            currentVersion = entry->value.isNull() ? emptyString() : entry->value.isolatedCopy();
            LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid, currentVersion.ascii().data());

            // Note: In multi-process browsers the cached value may be inaccurate, but
            // we cannot read the actual version from the database without potentially
            // inducing a form of deadlock, a busytimeout error when trying to
            // access the database. So we'll use the cached value if we're unable to read
            // the value from the database file without waiting.
            // FIXME: Add an async openDatabase method to the DatabaseAPI.
            const int noSqliteBusyWaitTime = 0;
            m_sqliteDatabase.setBusyTimeout(noSqliteBusyWaitTime);
            String versionFromDatabase;
            if (getVersionFromDatabase(versionFromDatabase, false)) {
                currentVersion = versionFromDatabase;
                updateGuidVersionMap(m_guid, currentVersion);
            }
            m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime);
        } else {
            LOG(StorageAPI, "No cached version for guid %i", m_guid);

            SQLiteTransaction transaction(m_sqliteDatabase);
            transaction.begin();
            if (!transaction.inProgress()) {
                reportOpenDatabaseResult(2, InvalidStateError, m_sqliteDatabase.lastError());
                errorMessage = formatErrorMessage("unable to open database, failed to start transaction", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
                m_sqliteDatabase.close();
                return false;
            }

            String tableName(infoTableName);
            if (!m_sqliteDatabase.tableExists(tableName)) {
                m_new = true;

                if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + tableName + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT NOT NULL ON CONFLICT FAIL);")) {
                    reportOpenDatabaseResult(3, InvalidStateError, m_sqliteDatabase.lastError());
                    errorMessage = formatErrorMessage("unable to open database, failed to create 'info' table", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
                    transaction.rollback();
                    m_sqliteDatabase.close();
                    return false;
                }
            } else if (!getVersionFromDatabase(currentVersion, false)) {
                reportOpenDatabaseResult(4, InvalidStateError, m_sqliteDatabase.lastError());
                errorMessage = formatErrorMessage("unable to open database, failed to read current version", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
                transaction.rollback();
                m_sqliteDatabase.close();
                return false;
            }

            if (currentVersion.length()) {
                LOG(StorageAPI, "Retrieved current version %s from database %s", currentVersion.ascii().data(), databaseDebugName().ascii().data());
            } else if (!m_new || shouldSetVersionInNewDatabase) {
                LOG(StorageAPI, "Setting version %s in database %s that was just created", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
                if (!setVersionInDatabase(m_expectedVersion, false)) {
                    reportOpenDatabaseResult(5, InvalidStateError, m_sqliteDatabase.lastError());
                    errorMessage = formatErrorMessage("unable to open database, failed to write current version", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
                    transaction.rollback();
                    m_sqliteDatabase.close();
                    return false;
                }
                currentVersion = m_expectedVersion;
            }
            updateGuidVersionMap(m_guid, currentVersion);
            transaction.commit();
        }
    }

    if (currentVersion.isNull()) {
        LOG(StorageAPI, "Database %s does not have its version set", databaseDebugName().ascii().data());
        currentVersion = "";
    }

    // If the expected version isn't the empty string, ensure that the current database version we have matches that version. Otherwise, set an exception.
    // If the expected version is the empty string, then we always return with whatever version of the database we have.
    if ((!m_new || shouldSetVersionInNewDatabase) && m_expectedVersion.length() && m_expectedVersion != currentVersion) {
        reportOpenDatabaseResult(6, InvalidStateError, 0);
        errorMessage = "unable to open database, version mismatch, '" + m_expectedVersion + "' does not match the currentVersion of '" + currentVersion + "'";
        m_sqliteDatabase.close();
        return false;
    }

    ASSERT(m_databaseAuthorizer);
    m_sqliteDatabase.setAuthorizer(m_databaseAuthorizer);

    // See comment at the top this file regarding calling addOpenDatabase().
    DatabaseTracker::tracker().addOpenDatabase(this);
    m_opened = true;

    // Declare success:
    error = DatabaseError::None; // Clear the presumed error from above.
    onExitCaller.setOpenSucceeded();

    if (m_new && !shouldSetVersionInNewDatabase)
        m_expectedVersion = ""; // The caller provided a creationCallback which will set the expected version.

    reportOpenDatabaseResult(0, -1, 0); // OK
    return true;
}
Example #27
0
JSValue jsOwnedStringOrNull(ExecState* exec, const String& s)
{
    if (s.isNull())
        return jsNull();
    return jsOwnedString(exec, s);
}
bool ResourceHandle::onRequestComplete()
{
    if (!d->m_internetHandle) { // 0 if canceled.
        deref(); // balances ref in start
        return false;
    }

    if (d->m_bytesRemainingToWrite) {
        DWORD bytesWritten;
        InternetWriteFile(d->m_requestHandle,
                          d->m_formData.data() + (d->m_formData.size() - d->m_bytesRemainingToWrite),
                          d->m_bytesRemainingToWrite,
                          &bytesWritten);
        d->m_bytesRemainingToWrite -= bytesWritten;
        if (d->m_bytesRemainingToWrite)
            return true;
        d->m_formData.clear();
    }

    if (!d->m_sentEndRequest) {
        HttpEndRequestW(d->m_requestHandle, 0, 0, reinterpret_cast<DWORD_PTR>(this));
        d->m_sentEndRequest = true;
        return true;
    }

    static const int bufferSize = 32768;
    char buffer[bufferSize];
    INTERNET_BUFFERSA buffers;
    buffers.dwStructSize = sizeof(INTERNET_BUFFERSA);
    buffers.lpvBuffer = buffer;
    buffers.dwBufferLength = bufferSize;

    BOOL ok = FALSE;
    while ((ok = InternetReadFileExA(d->m_requestHandle, &buffers, d->m_loadSynchronously ? 0 : IRF_NO_WAIT, reinterpret_cast<DWORD_PTR>(this))) && buffers.dwBufferLength) {
        if (!d->m_hasReceivedResponse) {
            d->m_hasReceivedResponse = true;

            ResourceResponse response;
            response.setURL(firstRequest().url());

            String httpStatusText = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_STATUS_TEXT);
            if (!httpStatusText.isNull())
                response.setHTTPStatusText(httpStatusText);

            String httpStatusCode = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_STATUS_CODE);
            if (!httpStatusCode.isNull())
                response.setHTTPStatusCode(httpStatusCode.toInt());

            String httpContentLength = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_CONTENT_LENGTH);
            if (!httpContentLength.isNull())
                response.setExpectedContentLength(httpContentLength.toInt());

            String httpContentType = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_CONTENT_TYPE);
            if (!httpContentType.isNull()) {
                response.setMimeType(extractMIMETypeFromMediaType(httpContentType));
                response.setTextEncodingName(extractCharsetFromMediaType(httpContentType));
            }

            if (ResourceHandleClient* resourceHandleClient = client())
                resourceHandleClient->didReceiveResponse(this, response);
        }

        if (ResourceHandleClient* resourceHandleClient = client())
            resourceHandleClient->didReceiveData(this, buffer, buffers.dwBufferLength, 0);
        buffers.dwBufferLength = bufferSize;
    }

    if (!ok && GetLastError() == ERROR_IO_PENDING)
        return true;

    if (ResourceHandleClient* resourceHandleClient = client())
        resourceHandleClient->didFinishLoading(this, 0);

    InternetCloseHandle(d->m_requestHandle);
    InternetCloseHandle(d->m_connectHandle);
    deref(); // balances ref in start
    return false;
}
void ImageLoader::updateFromElement()
{
    // If we're not making renderers for the page, then don't load images.  We don't want to slow
    // down the raw HTML parsing case by loading images we don't intend to display.
    Document* document = m_element->document();
    if (!document->renderer())
        return;

    AtomicString attr = m_element->imageSourceURL();

    if (!m_failedLoadURL.isEmpty() && attr == m_failedLoadURL)
        return;

    // Do not load any image if the 'src' attribute is missing or if it is
    // an empty string.
    CachedResourceHandle<CachedImage> newImage = 0;
    if (!attr.isNull() && !stripLeadingAndTrailingHTMLSpaces(attr).isEmpty()) {
        CachedResourceRequest request(ResourceRequest(document->completeURL(sourceURI(attr))));
        request.setInitiator(element());

        String crossOriginMode = m_element->fastGetAttribute(HTMLNames::crossoriginAttr);
        if (!crossOriginMode.isNull()) {
            StoredCredentials allowCredentials = equalIgnoringCase(crossOriginMode, "use-credentials") ? AllowStoredCredentials : DoNotAllowStoredCredentials;
            updateRequestForAccessControl(request.mutableResourceRequest(), document->securityOrigin(), allowCredentials);
        }

        if (m_loadManually) {
            bool autoLoadOtherImages = document->cachedResourceLoader()->autoLoadImages();
            document->cachedResourceLoader()->setAutoLoadImages(false);
            newImage = new CachedImage(request.resourceRequest());
            newImage->setLoading(true);
            newImage->setOwningCachedResourceLoader(document->cachedResourceLoader());
            document->cachedResourceLoader()->m_documentResources.set(newImage->url(), newImage.get());
            document->cachedResourceLoader()->setAutoLoadImages(autoLoadOtherImages);
        } else
            newImage = document->cachedResourceLoader()->requestImage(request);

        // If we do not have an image here, it means that a cross-site
        // violation occurred, or that the image was blocked via Content
        // Security Policy, or the page is being dismissed. Trigger an
        // error event if the page is not being dismissed.
        if (!newImage && !pageIsBeingDismissed(document)) {
            m_failedLoadURL = attr;
            m_hasPendingErrorEvent = true;
            errorEventSender().dispatchEventSoon(this);
        } else
            clearFailedLoadURL();
    } else if (!attr.isNull()) {
        // Fire an error event if the url is empty.
        // FIXME: Should we fire this event asynchronoulsy via errorEventSender()?
        m_element->dispatchEvent(Event::create(eventNames().errorEvent, false, false));
    }
    
    CachedImage* oldImage = m_image.get();
    if (newImage != oldImage) {
        if (m_hasPendingBeforeLoadEvent) {
            beforeLoadEventSender().cancelEvent(this);
            m_hasPendingBeforeLoadEvent = false;
        }
        if (m_hasPendingLoadEvent) {
            loadEventSender().cancelEvent(this);
            m_hasPendingLoadEvent = false;
        }

        // Cancel error events that belong to the previous load, which is now cancelled by changing the src attribute.
        // If newImage is null and m_hasPendingErrorEvent is true, we know the error event has been just posted by
        // this load and we should not cancel the event.
        // FIXME: If both previous load and this one got blocked with an error, we can receive one error event instead of two.
        if (m_hasPendingErrorEvent && newImage) {
            errorEventSender().cancelEvent(this);
            m_hasPendingErrorEvent = false;
        }

        m_image = newImage;
        m_hasPendingBeforeLoadEvent = !m_element->document()->isImageDocument() && newImage;
        m_hasPendingLoadEvent = newImage;
        m_imageComplete = !newImage;

        if (newImage) {
            if (!m_element->document()->isImageDocument()) {
                if (!m_element->document()->hasListenerType(Document::BEFORELOAD_LISTENER))
                    dispatchPendingBeforeLoadEvent();
                else
                    beforeLoadEventSender().dispatchEventSoon(this);
            } else
                updateRenderer();

            // If newImage is cached, addClient() will result in the load event
            // being queued to fire. Ensure this happens after beforeload is
            // dispatched.
            newImage->addClient(this);
        } else {
            updateRenderer();
        }

        if (oldImage)
            oldImage->removeClient(this);
    }

    if (RenderImageResource* imageResource = renderImageResource())
        imageResource->resetAnimation();

    // Only consider updating the protection ref-count of the Element immediately before returning
    // from this function as doing so might result in the destruction of this ImageLoader.
    updatedHasPendingEvent();
}
static size_t contentSizeInBytes(const String& content)
{
    return content.isNull() ? 0 : content.impl()->sizeInBytes();
}