public static function urlRewriter($content, $code)
    {
        if (!is_callable($code)) {
            throw new InvalidArgumentException(
                'HTTP::urlRewriter expects a callable as the second parameter'
            );
        }

        // Replace attributes
        $attribs = ["src", "background", "a" => "href", "link" => "href", "base" => "href"];
        $regExps = [];
        foreach ($attribs as $tag => $attrib) {
            if (!is_numeric($tag)) {
                $tagPrefix = "$tag ";
            } else {
                $tagPrefix = "";
            }

            $regExps[] = "/(<{$tagPrefix}[^>]*$attrib *= *\")([^\"]*)(\")/i";
            $regExps[] = "/(<{$tagPrefix}[^>]*$attrib *= *')([^']*)(')/i";
            $regExps[] = "/(<{$tagPrefix}[^>]*$attrib *= *)([^\"' ]*)( )/i";
        }
        // Replace css styles
        // @todo - http://www.css3.info/preview/multiple-backgrounds/
        $styles = ['background-image', 'background', 'list-style-image', 'list-style', 'content'];
        foreach ($styles as $style) {
            $regExps[] = "/($style:[^;]*url *\\(\")([^\"]+)(\"\\))/i";
            $regExps[] = "/($style:[^;]*url *\\(')([^']+)('\\))/i";
            $regExps[] = "/($style:[^;]*url *\\()([^\"\\)')]+)(\\))/i";
        }

        // Callback for regexp replacement
        $callback = function ($matches) use ($code) {
            // Decode HTML attribute
            $URL = Convert::xml2raw($matches[2]);
            $rewritten = $code($URL);
            return $matches[1] . Convert::raw2xml($rewritten) . $matches[3];
        };

        // Execute each expression
        foreach ($regExps as $regExp) {
            $content = preg_replace_callback($regExp, $callback, $content);
        }

        return $content;
    }