Pergunta

Eu tenho um aplicativo que envia uma solicitação POST para o fórum de software VB e registra alguém em (sem definir cookies ou qualquer coisa).

Uma vez que o usuário está logado I criar uma variável que cria um caminho em sua máquina local.

c: \ TempFolder \ data \ username

O problema é que alguns nomes estão jogando "caracteres ilegais" exceção. Por exemplo, se meu nome de usuário foi mas|fenix seria lançar uma exceção ..

Path.Combine( _      
  Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData), _
  DateTime.Now.ToString("ddMMyyhhmm") + "-" + form1.username)

Eu não quero removê-lo da cadeia, mas uma pasta com seu nome de usuário é criado através de FTP em um servidor. E isso leva a minha segunda pergunta. Se eu estou criando uma pasta no servidor que pode deixar os "caracteres ilegais" em? Só peço isso porque o servidor é baseado em Linux, e eu não tenho certeza se Linux aceita ou não.

EDIT: Parece que codificam URL não é o que eu quero .. Aqui está o que eu quero fazer:

old username = mas|fenix
new username = mas%xxfenix

Onde% xx é o valor ASCII ou qualquer outro valor que seria facilmente identificar o caráter.

Foi útil?

Solução

Edit: Note que esta resposta está agora fora de data. Veja a resposta de Siarhei Kuchuk abaixo para uma correção melhor

URLEncoding vai fazer o que você está sugerindo aqui. Com C #, você simplesmente usar HttpUtility, como mencionado.

Você também pode Regex os caracteres ilegais e, em seguida, substituir, mas isso fica muito mais complexo, como você vai ter que ter alguma forma de máquina de estado (interruptor ... caso, por exemplo) para substituir com os caracteres corretos. Desde UrlEncode faz isso da frente para cima, é bastante fácil.

Como para Linux contra janelas, existem alguns personagens que são aceitáveis ??em Linux que não são no Windows, mas eu não me preocuparia com isso, como o nome da pasta pode ser retornado pela decodificação da seqüência de URL, usando UrlDecode, para que pode ida e volta as alterações.

Outras dicas

Eu tenho experimentado com os vários métodos .NET fornecem para a codificação de URL. Talvez a tabela a seguir será útil (como a saída de um aplicativo de teste que eu escrevi):

Unencoded UrlEncoded UrlEncodedUnicode UrlPathEncoded EscapedDataString EscapedUriString HtmlEncoded HtmlAttributeEncoded HexEscaped
A         A          A                 A              A                 A                A           A                    %41
B         B          B                 B              B                 B                B           B                    %42

a         a          a                 a              a                 a                a           a                    %61
b         b          b                 b              b                 b                b           b                    %62

0         0          0                 0              0                 0                0           0                    %30
1         1          1                 1              1                 1                1           1                    %31

[space]   +          +                 %20            %20               %20              [space]     [space]              %20
!         !          !                 !              !                 !                !           !                    %21
"         %22        %22               "              %22               %22              "      "               %22
#         %23        %23               #              %23               #                #           #                    %23
$         %24        %24               $              %24               $                $           $                    %24
%         %25        %25               %              %25               %25              %           %                    %25
&         %26        %26               &              %26               &                &       &                %26
'         %27        %27               '              '                 '                '       '                %27
(         (          (                 (              (                 (                (           (                    %28
)         )          )                 )              )                 )                )           )                    %29
*         *          *                 *              %2A               *                *           *                    %2A
+         %2b        %2b               +              %2B               +                +           +                    %2B
,         %2c        %2c               ,              %2C               ,                ,           ,                    %2C
-         -          -                 -              -                 -                -           -                    %2D
.         .          .                 .              .                 .                .           .                    %2E
/         %2f        %2f               /              %2F               /                /           /                    %2F
:         %3a        %3a               :              %3A               :                :           :                    %3A
;         %3b        %3b               ;              %3B               ;                ;           ;                    %3B
<         %3c        %3c               <              %3C               %3C              &lt;        &lt;                 %3C
=         %3d        %3d               =              %3D               =                =           =                    %3D
>         %3e        %3e               >              %3E               %3E              &gt;        >                    %3E
?         %3f        %3f               ?              %3F               ?                ?           ?                    %3F
@         %40        %40               @              %40               @                @           @                    %40
[         %5b        %5b               [              %5B               %5B              [           [                    %5B
\         %5c        %5c               \              %5C               %5C              \           \                    %5C
]         %5d        %5d               ]              %5D               %5D              ]           ]                    %5D
^         %5e        %5e               ^              %5E               %5E              ^           ^                    %5E
_         _          _                 _              _                 _                _           _                    %5F
`         %60        %60               `              %60               %60              `           `                    %60
{         %7b        %7b               {              %7B               %7B              {           {                    %7B
|         %7c        %7c               |              %7C               %7C              |           |                    %7C
}         %7d        %7d               }              %7D               %7D              }           }                    %7D
~         %7e        %7e               ~              ~                 ~                ~           ~                    %7E

Ā         %c4%80     %u0100            %c4%80         %C4%80            %C4%80           Ā           Ā                    [OoR]
ā         %c4%81     %u0101            %c4%81         %C4%81            %C4%81           ā           ā                    [OoR]
Ē         %c4%92     %u0112            %c4%92         %C4%92            %C4%92           Ē           Ē                    [OoR]
ē         %c4%93     %u0113            %c4%93         %C4%93            %C4%93           ē           ē                    [OoR]
Ī         %c4%aa     %u012a            %c4%aa         %C4%AA            %C4%AA           Ī           Ī                    [OoR]
ī         %c4%ab     %u012b            %c4%ab         %C4%AB            %C4%AB           ī           ī                    [OoR]
Ō         %c5%8c     %u014c            %c5%8c         %C5%8C            %C5%8C           Ō           Ō                    [OoR]
ō         %c5%8d     %u014d            %c5%8d         %C5%8D            %C5%8D           ō           ō                    [OoR]
Ū         %c5%aa     %u016a            %c5%aa         %C5%AA            %C5%AA           Ū           Ū                    [OoR]
ū         %c5%ab     %u016b            %c5%ab         %C5%AB            %C5%AB           ū           ū                    [OoR]

As colunas representam codificações da seguinte forma:

  • urlencoded: HttpUtility.UrlEncode

  • UrlEncodedUnicode: HttpUtility.UrlEncodeUnicode

  • UrlPathEncoded: HttpUtility.UrlPathEncode

  • EscapedDataString: Uri.EscapeDataString

  • EscapedUriString: Uri.EscapeUriString

  • HTMLEncoded: HttpUtility.HtmlEncode

  • HtmlAttributeEncoded: HttpUtility.HtmlAttributeEncode

  • HexEscaped: Uri.HexEscape

NOTAS:

  1. HexEscape só pode lidar com os primeiros 255 caracteres. Por isso, lança uma exceção ArgumentOutOfRange para os personagens Latina A-estendidos (por exemplo, a).

  2. Esta tabela foi gerada em .NET 4.0 (veja o comentário de Levi Botelho abaixo daquela diz a codificação em .NET 4.5 é ligeiramente diferente).

EDIT:

Eu adicionei uma segunda tabela com as codificações para .NET 4.5. Veja esta resposta: https://stackoverflow.com/a/21771206/216440

EDIT 2:

Uma vez que as pessoas parecem apreciar estas tabelas, eu pensei que você pode gostar o código-fonte que gera a mesa, assim você pode jogar em torno de si. É um aplicativo de console simples C #, que pode atingir qualquer .NET 4.0 ou 4.5:

using System;
using System.Collections.Generic;
using System.Text;
// Need to add a Reference to the System.Web assembly.
using System.Web;

namespace UriEncodingDEMO2
{
    class Program
    {
        static void Main(string[] args)
        {
            EncodeStrings();

            Console.WriteLine();
            Console.WriteLine("Press any key to continue...");
            Console.Read();
        }

        public static void EncodeStrings()
        {
            string stringToEncode = "ABCD" + "abcd"
            + "0123" + " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" + "ĀāĒēĪīŌōŪū";

            // Need to set the console encoding to display non-ASCII characters correctly (eg the 
            //  Latin A-Extended characters such as ĀāĒē...).
            Console.OutputEncoding = Encoding.UTF8;

            // Will also need to set the console font (in the console Properties dialog) to a font 
            //  that displays the extended character set correctly.
            // The following fonts all display the extended characters correctly:
            //  Consolas
            //  DejaVu Sana Mono
            //  Lucida Console

            // Also, in the console Properties, set the Screen Buffer Size and the Window Size 
            //  Width properties to at least 140 characters, to display the full width of the 
            //  table that is generated.

            Dictionary<string, Func<string, string>> columnDetails =
                new Dictionary<string, Func<string, string>>();
            columnDetails.Add("Unencoded", (unencodedString => unencodedString));
            columnDetails.Add("UrlEncoded",
                (unencodedString => HttpUtility.UrlEncode(unencodedString)));
            columnDetails.Add("UrlEncodedUnicode",
                (unencodedString => HttpUtility.UrlEncodeUnicode(unencodedString)));
            columnDetails.Add("UrlPathEncoded",
                (unencodedString => HttpUtility.UrlPathEncode(unencodedString)));
            columnDetails.Add("EscapedDataString",
                (unencodedString => Uri.EscapeDataString(unencodedString)));
            columnDetails.Add("EscapedUriString",
                (unencodedString => Uri.EscapeUriString(unencodedString)));
            columnDetails.Add("HtmlEncoded",
                (unencodedString => HttpUtility.HtmlEncode(unencodedString)));
            columnDetails.Add("HtmlAttributeEncoded",
                (unencodedString => HttpUtility.HtmlAttributeEncode(unencodedString)));
            columnDetails.Add("HexEscaped",
                (unencodedString
                    =>
                    {
                        // Uri.HexEscape can only handle the first 255 characters so for the 
                        //  Latin A-Extended characters, such as A, it will throw an 
                        //  ArgumentOutOfRange exception.                       
                        try
                        {
                            return Uri.HexEscape(unencodedString.ToCharArray()[0]);
                        }
                        catch
                        {
                            return "[OoR]";
                        }
                    }));

            char[] charactersToEncode = stringToEncode.ToCharArray();
            string[] stringCharactersToEncode = Array.ConvertAll<char, string>(charactersToEncode,
                (character => character.ToString()));
            DisplayCharacterTable<string>(stringCharactersToEncode, columnDetails);
        }

        private static void DisplayCharacterTable<TUnencoded>(TUnencoded[] unencodedArray,
            Dictionary<string, Func<TUnencoded, string>> mappings)
        {
            foreach (string key in mappings.Keys)
            {
                Console.Write(key.Replace(" ", "[space]") + " ");
            }
            Console.WriteLine();

            foreach (TUnencoded unencodedObject in unencodedArray)
            {
                string stringCharToEncode = unencodedObject.ToString();
                foreach (string columnHeader in mappings.Keys)
                {
                    int columnWidth = columnHeader.Length + 1;
                    Func<TUnencoded, string> encoder = mappings[columnHeader];
                    string encodedString = encoder(unencodedObject);

                    // ASSUMPTION: Column header will always be wider than encoded string.
                    Console.Write(encodedString.Replace(" ", "[space]").PadRight(columnWidth));
                }
                Console.WriteLine();
            }
        }
    }
}

Você deve codificar apenas o nome do usuário ou outra parte do URL que pode ser inválido. URL que codifica uma URL pode levar a problemas desde algo como isto:

string url = HttpUtility.UrlEncode("http://www.google.com/search?q=Example");

Será que deu

http% 3A% 2F% 2fwww.google.com% 2fsearch% 3fq% 3dExample

Esta é, obviamente, não vai funcionar bem. Em vez disso, você deve codificar apenas o valor do par chave / valor na cadeia de consulta, como este:

string url = "http://www.google.com/search?q=" + HttpUtility.UrlEncode("Example");

Esperemos que isso ajuda. Além disso, como teedyay mencionado, você ainda precisa ter certeza ilegal de arquivos caracteres -name são removidos ou então o sistema de arquivos não vai gostar do caminho.

Desde .NET Framework 4.5 e .NET padrão 1.0 você deve usar WebUtility.UrlEncode . Vantagens sobre alternativas:

  1. É parte do .NET Framework 4.5 +, .NET Núcleo 1.0+, .NET padrão 1.0+, UWP 10.0+ e todas as plataformas Xamarin também. HttpUtility , sendo disponível no .NET Framework anteriormente (.NET Framework 1.1+), torna-se disponível em outras plataformas muito mais tarde (.NET Núcleo 2.0+, .NET padrão 2.0+) e ainda não disponível no UWP (veja pergunta relacionada ).

  2. Na .NET Framework, ele reside em System.dll , por isso não necessita de quaisquer referências adicionais, ao contrário HttpUtility.

  3. escapa corretamente caracteres para URLs , Uri.EscapeUriString ao contrário (ver comentários a de drweb86 resposta ).

  4. não tem qualquer limite no comprimento da corda , Uri.EscapeDataString ao contrário (ver questão relacionada ), para que ele possa ser usado para solicitações POST, por exemplo.

Melhor maneira é usar

Uri.EscapeUriString

para não fazer referência perfil completo de .net 4.

Levi Botelho comentou que a tabela de codificações que foi gerado anteriormente não é mais precisa for .NET 4.5, uma vez que as codificações mudou ligeiramente entre .NET 4.0 e 4.5. Então eu regenerado a mesa for .NET 4.5:

Unencoded UrlEncoded UrlEncodedUnicode UrlPathEncoded WebUtilityUrlEncoded EscapedDataString EscapedUriString HtmlEncoded HtmlAttributeEncoded WebUtilityHtmlEncoded HexEscaped
A         A          A                 A              A                    A                 A                A           A                    A                     %41
B         B          B                 B              B                    B                 B                B           B                    B                     %42

a         a          a                 a              a                    a                 a                a           a                    a                     %61
b         b          b                 b              b                    b                 b                b           b                    b                     %62

0         0          0                 0              0                    0                 0                0           0                    0                     %30
1         1          1                 1              1                    1                 1                1           1                    1                     %31

[space]   +          +                 %20            +                    %20               %20              [space]     [space]              [space]               %20
!         !          !                 !              !                    %21               !                !           !                    !                     %21
"         %22        %22               "              %22                  %22               %22              &quot;      &quot;               &quot;                %22
#         %23        %23               #              %23                  %23               #                #           #                    #                     %23
$         %24        %24               $              %24                  %24               $                $           $                    $                     %24
%         %25        %25               %              %25                  %25               %25              %           %                    %                     %25
&         %26        %26               &              %26                  %26               &                &amp;       &amp;                &amp;                 %26
'         %27        %27               '              %27                  %27               '                &#39;       &#39;                &#39;                 %27
(         (          (                 (              (                    %28               (                (           (                    (                     %28
)         )          )                 )              )                    %29               )                )           )                    )                     %29
*         *          *                 *              *                    %2A               *                *           *                    *                     %2A
+         %2b        %2b               +              %2B                  %2B               +                +           +                    +                     %2B
,         %2c        %2c               ,              %2C                  %2C               ,                ,           ,                    ,                     %2C
-         -          -                 -              -                    -                 -                -           -                    -                     %2D
.         .          .                 .              .                    .                 .                .           .                    .                     %2E
/         %2f        %2f               /              %2F                  %2F               /                /           /                    /                     %2F
:         %3a        %3a               :              %3A                  %3A               :                :           :                    :                     %3A
;         %3b        %3b               ;              %3B                  %3B               ;                ;           ;                    ;                     %3B
<         %3c        %3c               <              %3C                  %3C               %3C              &lt;        &lt;                 &lt;                  %3C
=         %3d        %3d               =              %3D                  %3D               =                =           =                    =                     %3D
>         %3e        %3e               >              %3E                  %3E               %3E              &gt;        >                    &gt;                  %3E
?         %3f        %3f               ?              %3F                  %3F               ?                ?           ?                    ?                     %3F
@         %40        %40               @              %40                  %40               @                @           @                    @                     %40
[         %5b        %5b               [              %5B                  %5B               [                [           [                    [                     %5B
\         %5c        %5c               \              %5C                  %5C               %5C              \           \                    \                     %5C
]         %5d        %5d               ]              %5D                  %5D               ]                ]           ]                    ]                     %5D
^         %5e        %5e               ^              %5E                  %5E               %5E              ^           ^                    ^                     %5E
_         _          _                 _              _                    _                 _                _           _                    _                     %5F
`         %60        %60               `              %60                  %60               %60              `           `                    `                     %60
{         %7b        %7b               {              %7B                  %7B               %7B              {           {                    {                     %7B
|         %7c        %7c               |              %7C                  %7C               %7C              |           |                    |                     %7C
}         %7d        %7d               }              %7D                  %7D               %7D              }           }                    }                     %7D
~         %7e        %7e               ~              %7E                  ~                 ~                ~           ~                    ~                     %7E

Ā         %c4%80     %u0100            %c4%80         %C4%80               %C4%80            %C4%80           Ā           Ā                    Ā                     [OoR]
ā         %c4%81     %u0101            %c4%81         %C4%81               %C4%81            %C4%81           ā           ā                    ā                     [OoR]
Ē         %c4%92     %u0112            %c4%92         %C4%92               %C4%92            %C4%92           Ē           Ē                    Ē                     [OoR]
ē         %c4%93     %u0113            %c4%93         %C4%93               %C4%93            %C4%93           ē           ē                    ē                     [OoR]
Ī         %c4%aa     %u012a            %c4%aa         %C4%AA               %C4%AA            %C4%AA           Ī           Ī                    Ī                     [OoR]
ī         %c4%ab     %u012b            %c4%ab         %C4%AB               %C4%AB            %C4%AB           ī           ī                    ī                     [OoR]
Ō         %c5%8c     %u014c            %c5%8c         %C5%8C               %C5%8C            %C5%8C           Ō           Ō                    Ō                     [OoR]
ō         %c5%8d     %u014d            %c5%8d         %C5%8D               %C5%8D            %C5%8D           ō           ō                    ō                     [OoR]
Ū         %c5%aa     %u016a            %c5%aa         %C5%AA               %C5%AA            %C5%AA           Ū           Ū                    Ū                     [OoR]
ū         %c5%ab     %u016b            %c5%ab         %C5%AB               %C5%AB            %C5%AB           ū           ū                    ū                     [OoR]

As colunas representam codificações da seguinte forma:

  • urlencoded: HttpUtility.UrlEncode
  • UrlEncodedUnicode: HttpUtility.UrlEncodeUnicode
  • UrlPathEncoded: HttpUtility.UrlPathEncode
  • WebUtilityUrlEncoded: WebUtility.UrlEncode
  • EscapedDataString: Uri.EscapeDataString
  • EscapedUriString: Uri.EscapeUriString
  • HTMLEncoded: HttpUtility.HtmlEncode
  • HtmlAttributeEncoded: HttpUtility.HtmlAttributeEncode
  • WebUtilityHtmlEncoded: WebUtility.HtmlEncode
  • HexEscaped: Uri.HexEscape

NOTAS:

  1. HexEscape só pode lidar com os primeiros 255 caracteres. Por isso, lança uma exceção ArgumentOutOfRange para os personagens Latina A-estendidos (por exemplo, a).

  2. Esta tabela foi gerada em .NET 4.5 (ver resposta https://stackoverflow.com/a/11236038/216440 para as codificações relevantes para .NET 4.0 e abaixo).

EDIT:

  1. Como resultado da resposta da Discórdia eu adicionei os novos métodos WebUtility UrlEncode e HTMLEncode, que foram introduzidos no .NET 4.5.

Url Encoding é fácil em .NET. Use:

System.Web.HttpUtility.UrlEncode(string url)

Se isso vai ser decodificado para obter o nome da pasta, você ainda vai precisar para excluir caracteres que não podem ser usados ??em nomes de pastas (*,?, /, Etc.)

Se você não pode ver System.Web, altere as configurações do projeto. A estrutura de destino deve ser ".NET Framework 4" em vez de" .NET Framework 4 Client Profile "

A implementação .NET de UrlEncode não está de acordo com a RFC 3986.

  1. Alguns caracteres não são codificados, mas deveria ser. Os personagens !()* estão listados na seção do RFC 2.2 como um caracteres reservados que devem ser codificadas ainda .NET falhar para codificar esses caracteres.

  2. Alguns caracteres são codificados, mas não deve ser. Os personagens .-_ não estão listados na seção do RFC 2.2 como um caractere reservado que não deve ser codificado ainda .NET erroneamente codifica esses caracteres.

  3. Os especifica RFC que, para ser consistente, implementações deve usar maiúsculas HEXDIG, onde .NET produz minúsculas HEXDIG.

Eu escrevi um método C # que url-codifica todos os símbolos:

    /// <summary>
    /// !#$345Hf} → %21%23%24%33%34%35%48%66%7D
    /// </summary>
    public static string UrlEncodeExtended( string value )
    {
        char[] chars = value.ToCharArray();
        StringBuilder encodedValue = new StringBuilder();
        foreach (char c in chars)
        {
            encodedValue.Append( "%" + ( (int)c ).ToString( "X2" ) );
        }
        return encodedValue.ToString();
    }

Idealmente, estes iria em uma classe chamada "filenaming" ou talvez apenas renomear Encode para "FileNameEncode". Nota: estes não são projetados para lidar com caminhos completos, apenas a pasta e / ou nomes de arquivo. Idealmente, você iria dividir ( "/") o seu caminho completo em primeiro lugar e, em seguida, verificar as peças. E, obviamente, em vez de uma união, você pode simplesmente adicionar o caractere "%" para a lista de caracteres não permitidos no Windows, mas eu acho que é mais útil / legível / factual desta forma. Decode () é exatamente o mesmo, mas muda o Replace (Uri.HexEscape (s [0]), s) "escapado" com o personagem.

public static List<string> urlEncodedCharacters = new List<string>
{
  "/", "\\", "<", ">", ":", "\"", "|", "?", "%" //and others, but not *
};
//Since this is a superset of urlEncodedCharacters, we won't be able to only use UrlEncode() - instead we'll use HexEncode
public static List<string> specialCharactersNotAllowedInWindows = new List<string>
{
  "/", "\\", "<", ">", ":", "\"", "|", "?", "*" //windows dissallowed character set
};

    public static string Encode(string fileName)
    {
        //CheckForFullPath(fileName); // optional: make sure it's not a path?
        List<string> charactersToChange = new List<string>(specialCharactersNotAllowedInWindows);
        charactersToChange.AddRange(urlEncodedCharacters.
            Where(x => !urlEncodedCharacters.Union(specialCharactersNotAllowedInWindows).Contains(x)));   // add any non duplicates (%)

        charactersToChange.ForEach(s => fileName = fileName.Replace(s, Uri.HexEscape(s[0])));   // "?" => "%3f"

        return fileName;
    }

Obrigado @ simon-tewsi para a tabela muito útil acima!

Além de resposta de @ Dan Herbert, Você devemos codificar apenas os valores em geral.

Split tem params parâmetros Split ( '&', '='); expressão em primeiro lugar dividida por e, em seguida, '=' elementos ímpares são então todos os valores a ser codificado a seguir apresentados.

public static void EncodeQueryString(ref string queryString)
{
    var array=queryString.Split('&','=');
    for (int i = 0; i < array.Length; i++) {
        string part=array[i];
        if(i%2==1)
        {               
            part=System.Web.HttpUtility.UrlEncode(array[i]);
            queryString=queryString.Replace(array[i],part);
        }
    }
}

Eu acho que as pessoas aqui foi desviado pela mensagem UrlEncode. URLEncoding é não o que você quer -. Você quer coisas codificar que não vai funcionar como um nome de arquivo no sistema de destino

Assumindo que você quer alguma generalidade -. Sinta-se livre para encontrar os caracteres ilegais em vários sistemas (MacOS, Windows, Linux e Unix), sindicato-los para formar um conjunto de caracteres para escapar

Quanto à fuga, um HexEscape deve ser fino (Substituir os personagens com XX%). Converter cada personagem para UTF-8 bytes e codificar tudo> 128 se você quiser dar suporte a sistemas que não fazem unicode. Mas há outras maneiras, tais como o uso de barras invertidas "\" ou HTML codificação """. Você pode criar o seu próprio. Todos qualquer sistema tem que fazer é 'codificar' o caráter uncompatible de distância. Os sistemas acima permitem que você recriar o nome original -. mas algo como substituir os caracteres ruins com espaços também funciona

Na mesma tangente como acima, o único a utilização é

Uri.EscapeDataString

- Ele codifica tudo o que é necessário para OAuth, que não codifica as coisas que proíbe OAuth que codificam, e codifica o espaço como% 20 e não + (Também na OATH Spec) Ver: RFC 3986. AFAIK, este é o mais recente especificação URI.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top