IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Web & réseau Delphi Discussion :

WebSocket HTML5 et Delphi


Sujet :

Web & réseau Delphi

  1. #1
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2009
    Messages : 76
    Points : 42
    Points
    42
    Par défaut WebSocket HTML5 et Delphi
    Bonjour,

    Voilà avec la sortie des socket avec l'api d'HTML5. J'ai voulu comprendre un peut et essayer de le faire marcher avec un serveur en DELPHI.

    Alors côté navigateur tout bas bien j'envoie un requête le problème c'est que le serveur n'arrive pas à me répondre.
    Donc côté serveur:

    Voilà ma réponse:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
      s := 'HTTP/1.1 101 WebSocket Protocol Handshake' + #13#10 
        +  'Upgrade: WebSocket' + #13#10
        +  'Connection: Upgrade' + #13#10
        +  'Sec-WebSocket-Location: ws://.......' + #13#10
        +  'Sec-WebSocket-Origin: http://localhost' + #13#10
        +  'Sec-WebSocket-Protocol: sample' + #13#10
        + #13#10 + md5rep;
    Le "md5rep" lui est réaliser comme il se doit normalement avec les deux key de la requête et concaténés à la troisième key.

    Mais le ça ne marche pas je comprend pas

    help

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 676
    Points : 25 491
    Points
    25 491
    Par défaut
    Delphi ? Version ?
    Delphi On Rails ? ce n'est plus du Delphi mais du Ruby (c'est tout aussi éloigné de Delphi que l'est Delphi For PHP)

    Quel navigateur ? utilise FF4 ou Chrome pour un début de compatibilité du client avec les WebSockets !
    C'est tout de même très frais comme techno !

    Qu'est ce qui ne fonctionne pas ?
    Cette étape correspond à la phase de négociation du protocol, pour effectuer la connexion bi-directionnel en HTTP, ensuite, il y aura la phase d'acceptation du protocol (selon la version) puis après, c'est un peu tout le monde fait ce qu'il veut, principalement du streaming avec les composants HTML5 !

  3. #3
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    aucune idée

    comme à chaque fois que j'étudie un protocole, je fais toujours un client et un serveur...et idéalement je me trouve un client et un serveur déjà faits...ça me permet de tester des deux côtés du protocole et de repérer plus facilement mes erreurs.

  4. #4
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2009
    Messages : 76
    Points : 42
    Points
    42
    Par défaut
    Merci de votre aide alors,

    J'utilise DELPHI 7 et Chrome comme navigateur !

    Le problème vient surrment de la clé que je renvoie..

    Bizarre tout de même car j'ai fait ce qu'il fallait, le client reçoit comme si le serveur était fermé, or le serveur lui reçoit bien la requête donc c'est vraiment dans ma réponse...

    L'entête ma l'air correcte donc seul problème qui peut y avoir c'est le md5 que je revoie qui ne ne doit pas aller ?

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 676
    Points : 25 491
    Points
    25 491
    Par défaut
    As-tu essayé une version sans clé ?
    As-tu essayé une version avec une clé volontairement incorrect ?
    Pour voir si le comportement est similaire à celui que tu observes ?

    Quel est ta fonction de MD5 ?

    Sinon, ta syntaxe est déjà une version obsolète !
    Il semble que Chrome soit le seul qui supporte encore cette forme ! Je sais une source basique comme wikipedia est pas toujours fiable, mais cela peut-être aussi une explication à ton problème, tu as peut-être une version qui ne le supporte plus !

  6. #6
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2009
    Messages : 76
    Points : 42
    Points
    42
    Par défaut
    Une version sans clé ? Comment je fais pour envoyé sans clé il va me refusé car pour moi j'avais compris qu'il fallait renvoyé la clé pour que le client accepte?

    Je pense que le problème vient lors de la conversion au format binaire en 32bit:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
      for i := 0 to 3 do
      begin
        n1 := chr((p1 shr ((i and 7) shl 3)) and $ff) + n1;  
      end;
    Quant-à ma fonction md5:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    function TForm1.md5(const Input: String): String;
    var
      hCryptProvider: HCRYPTPROV;
      hHash: HCRYPTHASH;
      bHash: array[0..$7f] of Byte;
      dwHashBytes: Cardinal;
      pbContent: PByte;
      i: Integer;
     
    begin
      dwHashBytes := 16;
      pbContent := Pointer(PChar(Input));
     
      Result := '';
     
      if CryptAcquireContext(@hCryptProvider, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT or CRYPT_MACHINE_KEYSET) then
      begin
        if CryptCreateHash(hCryptProvider, CALG_MD5, 0, 0, @hHash) then
        begin
          if CryptHashData(hHash, pbContent, Length(Input) * sizeof(Char), 0) then
          begin
            if CryptGetHashParam(hHash, HP_HASHVAL, @bHash[0], @dwHashBytes, 0) then
            begin
              for i := 0 to dwHashBytes - 1 do
              begin
                Result := Result + Format('%.2x', [bHash[i]]);
              end;
            end;
          end;
          CryptDestroyHash(hHash);
        end;
     
        CryptReleaseContext(hCryptProvider, 0);
      end;
     
      Result := AnsiLowerCase(Result);
    end;

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 676
    Points : 25 491
    Points
    25 491
    Par défaut
    Citation Envoyé par shadow578 Voir le message
    Une version sans clé ? Comment je fais pour envoyé sans clé il va me refusé car pour moi j'avais compris qu'il fallait renvoyé la clé pour que le client accepte?
    C'est pour une ANALYSE !
    Tester les comportements d'erreur est très instructifs, souvent plus que de tester de nombreux cas dont le comportement n'est pas prévisible car incorrect !
    C'est le principe du TDD ! On écrit les Tests qui valident ou invalident une fonction avant de la coder, cela permet de garantir la spec !

    Format Binaire ???
    Semble que c'est une simple conversion de nombre

    1- As-tu retirer tous caractères autre que des Nombres dans ta clé ?
    2- As-tu diviser le nombre obtenu par le nombre d'espace ?

    Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
    Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
    8 Dernier Octets : ^n:ds[4U
    4146546015 / 5
    1299853100 / 5
    ^n:ds[4U
    Bon, je suis pas RainMan, je sais pas calculé ça !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    Key1, Key2 : Longword; // Normalement, les clés ne dépassent pas 32bits !
    Key1BE, Key2BE : Longword;
    NbSpace1, NbSpace2: Byte;
    Token : string;
     
     
    Key1 := WebSocketKeyToInt32(StringKey1);
    Key2 := WebSocketKeyToInt32(StringKey1);
    Key1BE := SwapLongword(Key1); // Semble que c'est du Big Endian !
    Key2BE := SwapLongword(Key2);
     
    SetLength(S, 16);
    CopyMemory(@Token[1], @Key1BE, 4);
    CopyMemory(@Token[5], @Key2BE, 4);
    CopyMemory(@Token[9], @ContentRequest[Length(ContentRequest) - 8 + 1], 8); // ContentRequest la chaine contenant le message, ^n:ds[4U étant les 8 derniers caractères
     
    ContentResponse := md5(Token);
    WebSocketKeyToInt32, va compter les espaces, concaténer tous les chiffres dans une chainer puis convertir en Entier 64 bits, diviser par le nombre d'espace, normalement le résultat doit être un entier 32 bits

    code tapé à l'arrache sur le forum

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    function WebSocketKeyToInt32(S: String): Longword;
    var
      StrValue: string;
      Int64Value: Int64;
      SpaceCount: Byte;
    begin
      StrValue := '';
      SpaceCount := 0;
     
      for i := 1 to length(S) do
      begin
        if S[i] in ['0'..'9'] then
         StrValue = StrValue + S[i]; // En Delphi 7, je te conseil soit d'utiliser FastMM soit de pre-compter les chiffres, les réalloctions de chaine c'est très lent ! 
        else
          if S[i] = ' ' then  
            Inc(SpaceCount);
      end;
     
      Int64Value := StrToInt64(StrValue);
      Result := Int64Value div SpaceCount;
    end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
       function SwapLongword(Value: Longword): Longword;
       {$IFDEF PUREPASCAL}
       type
          TMapLongword = array[0..3] of Byte;
       begin
          TMapLongword(Result)[0] := TMapLongword(Value)[3];
          TMapLongword(Result)[1] := TMapLongword(Value)[2];
          TMapLongword(Result)[2] := TMapLongword(Value)[1];
          TMapLongword(Result)[3] := TMapLongword(Value)[0];
       {$ELSE}
       asm
        BSWAP EAX
      {$ENDIF}
       end;

  8. #8
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2009
    Messages : 76
    Points : 42
    Points
    42
    Par défaut
    Oula qu'est ce que c'est que tout ça o_O

    Moi je ne fessait pas du tout comme çà je récupérer dans un boucle les nombres puis je compter les espaces auquel je divisais ma key1 puis je mettais en binaire 32 ...

    En essayant de reprendre ton code plusieurs élément que je ne compred pas :

    WebSocketKeyToInt32 ? une uses spécial ?

    ???

    @ContentRequest ??

    Merci en tout cas de m'aider

  9. #9
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 676
    Points : 25 491
    Points
    25 491
    Par défaut
    Citation Envoyé par shadow578 Voir le message
    Oula qu'est ce que c'est que tout ça o_O

    Moi je ne fessait pas du tout comme çà je récupérer dans un boucle les nombres puis je compter les espaces auquel je divisais ma key1 puis je mettais en binaire 32 ...
    la fonction WebSocketKeyToInt32 fait exactement ce que tu décrits !
    Fournit donc ton code !


    Citation Envoyé par shadow578 Voir le message
    En essayant de reprendre ton code plusieurs élément que je ne compred pas :

    WebSocketKeyToInt32 ? une uses spécial ?
    le code de la fonction est dans le sujet, merci de lire l'intégralité de la réponse avant de poster !

    Citation Envoyé par shadow578 Voir le message
    Un petit effort
    Citation Envoyé par shadow578 Voir le message
    @ContentRequest ??
    J'ai commenté !
    ContentRequest c'est le contenu du message HTTP, tu ne fournis pas les technos utiliser, j'utilises des termes communément admis en Delphi lors que l'on parle de TWebApplication

  10. #10
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2009
    Messages : 76
    Points : 42
    Points
    42
    Par défaut
    Bon je met mon code sa sera plus simple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
     
    procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    var s: string;
    begin
      s := Socket.ReceiveText;
      Memo1.Lines.Add(s);
      envoyerFichier(socket, s);
    end;
     
    procedure TForm1.envoyerFichier(Socket: TCustomWinSocket; nomFichier: String);
    var md5rep, s, data: string;
    begin
      md5rep := decodeEntete(nomFichier);
     
      s := 'HTTP/1.1 101 WebSocket Protocol Handshake' + #13#10 
        +  'Upgrade: WebSocket' + #13#10
        +  'Connection: Upgrade' + #13#10
        +  'Sec-WebSocket-Location: ws://exemple../' + #13#10
        +  'Sec-WebSocket-Origin: http://localhost' + #13#10
        +  'Sec-WebSocket-Protocol: sample' + #13#10
        + #13#10 + md5rep;
     
     
      Memo1.Lines.Add(s);
      Socket.SendText(s);
    end;
     
     
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Memo1.Clear;
    end;
     
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      ServerSocket1.Open;
    end;
     
    function TForm1.decodeEntete(s:string):string;
    var i: integer;
      key1, key2, data: string;
    begin
    data := ''; key1 := ''; key2:='';
      For i := 1 to 10 do begin
        if(pos('Sec-WebSocket-Key1: ', Memo1.Lines[i]) > 0) then
          key1 := Memo1.Lines[i]
        else if(pos('Sec-WebSocket-Key2: ', Memo1.Lines[i]) > 0) then
          key2 := Memo1.Lines[i]
        else if(i=9)then data := Memo1.Lines[i];
      end;
     
      key1 := copy(key1, 21, length(key1));
      key2 := copy(key2, 21, length(key2));
     
      Memo1.Lines.Add(#13#10+'key1: '+key1+#13#10+'key2: '+key2+#13#10+'key3: '+data+#13#10);
     
      if not(length(data) <> 8) then
        result := Hixie76Signature(key1, key2, data)
      else Memo1.Lines.Add('bad plus de 8');
    end;
     
    function Tform1.Hixie76Signature(key1, key2, data: string): string;
    var test, n1, n2, totalKey: string;
        i, s1, s2: integer;
        p1, p2: int64;
    begin
      result := '';
      s1 := 0;
      n1 := '';
      s2 := 0;
      n2 := '';
      for i := 1 to length(key1) do
      begin
        if ((key1[i] >= '0') and (key1[i] <= '9')) then
          n1 := n1 + key1[i];
        if (key1[i] = ' ') then
          inc(s1);
      end;
      for i := 1 to length(key2) do
      begin
        if ((key2[i] >= '0') and (key2[i] <= '9')) then
          n2 := n2 + key2[i];
        if (key2[i] = ' ') then
          inc(s2);
      end;
      p1 := StrToInt64(n1) div s1;
      p2 := StrToInt64(n2) div s2;
     
      n1 := '';
      for i := 0 to 3 do
      begin
        n1 := chr((p1 shr ((i and 7) shl 3)) and $ff) + n1;  // convertion binaire sous 32bits
      end;
      n2 := '';
      for i := 0 to 3 do
      begin
        n2 := chr((p2 shr ((i and 7) shl 3)) and $ff) + n2;
      end;
     
     
      totalKey := n1 + n2 + UTF8Decode(data);
      result := md5(totalKey);
    end;
     
    function TForm1.md5(const Input: String): String;
    var
      hCryptProvider: HCRYPTPROV;
      hHash: HCRYPTHASH;
      bHash: array[0..$7f] of Byte;
      dwHashBytes: Cardinal;
      pbContent: PByte;
      i: Integer;
     
    begin
      dwHashBytes := 16;
      pbContent := Pointer(PChar(Input));
     
      Result := '';
     
      if CryptAcquireContext(@hCryptProvider, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT or CRYPT_MACHINE_KEYSET) then
      begin
        if CryptCreateHash(hCryptProvider, CALG_MD5, 0, 0, @hHash) then
        begin
          if CryptHashData(hHash, pbContent, Length(Input) * sizeof(Char), 0) then
          begin
            if CryptGetHashParam(hHash, HP_HASHVAL, @bHash[0], @dwHashBytes, 0) then
            begin
              for i := 0 to dwHashBytes - 1 do
              begin
                Result := Result + Format('%.2x', [bHash[i]]);
              end;
            end;
          end;
          CryptDestroyHash(hHash);
        end;
     
        CryptReleaseContext(hCryptProvider, 0);
      end;
     
      Result := AnsiLowerCase(Result);
    end;
    De mon côté je vais tenter ce que tu me propose...

    Merci en tout cas de ton aide!

  11. #11
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 676
    Points : 25 491
    Points
    25 491
    Par défaut
    Attention data peut faire plus de 8 bytes !
    C'est à toi de le gérer et de récupérer les 8 dernier bytes !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if ((key1[i] >= '0') and (key1[i] <= '9')) then
          n1 := n1 + key1[i];
    pour faciliter la lecture, autant mettre les bornes dans le sens de la lecture !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if (('0' <= key1[i]) and (key1[i] <= '9')) then
          n1 := n1 + key1[i];
    plus court
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if key1[i] in ['0'..'9'] then
          n1 := n1 + key1[i];
    Pour ta conversion, euh, qu'est-ce que c'est que tout ce calcul ???

    Pourquoi cette vilaine manie d'utiliser String pour du stockage de binaire ???
    Array of Byte ou TMemoryStream, il faut utiliser des types fiables, non optimisés !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for i := 0 to 3 do
      begin
        n1 := chr((p1 shr ((i and 7) shl 3)) and $ff) + n1;  // convertion binaire sous 32bits
      end;
    on va décomposer !

    (i and 7)

    i étant compris entre 0 et 3
    ce qui donne
    0000
    0001
    0010
    0100
    hors 7 = 0111
    donc (i and 7) = i donc inutile

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for i := 0 to 3 do
      begin
        n1 := chr((p1 shr (i shl 3)) and $ff) + n1;  // convertion binaire sous 32bits
      end;
    J'ai un peu de mal à savoir ce que cela donne !

    Selon les Specs
    et l'exemple fourni

    For each of these fields, the server has to take the digits from the
    value to obtain a number (in this case 1868545188 and 1733470270
    respectively), then divide that number by the number of spaces
    characters in the value (in this case 12 and 10) to obtain a 32-bit
    number (155712099 and 173347027). These two resulting numbers are
    then used in the server handshake, as described below.
    Il me semble que cela ne dépasse jamais 32 Bits !
    Dans ton décalage si i = 3, alors ça donne un shr 32, tu lit le 5 eme octet de ton Int64, je ne sais si c'est bon ça !

    Tu procèdes à un UTF8Decode, mais tu te rends compte que la chaine obtenu peut varier de 8 à 16 octets dépassant allégrement la taille requise !
    Tu dois donc uniquement conserver les 8 derniers octets (je parle bien d'octet pas de caractère, notion tellement trompeuse)

    As-tu testé ton code avec des valeurs connus issues des specs ou de wikipedia, cela te permettra de tester plus facilement ton propre hors de Chrome, hors des sockets, juste un Test !

  12. #12
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2009
    Messages : 76
    Points : 42
    Points
    42
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
     
    function Tform1.Hixie76Signature(key1, key2, head: string): string;
    var test, n1, n2, data: string;
        i, s1, s2: integer;
        p1, p2: int64;
    begin
      result := '';
      s1 := 0;
      n1 := '';
      s2 := 0;
      n2 := '';
     
     data := copy(head, Length(head)-8, Length(head));
     
      for i := 1 to length(key1) do
      begin
        if key1[i] in ['0'..'9'] then
          n1 := n1 + key1[i];
        if (key1[i] = ' ') then
          inc(s1);
      end;
      for i := 1 to length(key2) do
      begin
       if key2[i] in ['0'..'9'] then
          n2 := n2 + key2[i];
        if (key2[i] = ' ') then
          inc(s2);
      end;
      p1 := StrToInt64(n1) div s1;
      p2 := StrToInt64(n2) div s2;
     
      n1 := '';
      for i := 0 to 3 do
      begin
        n1 := chr((p1 shr (i shl 3)) and $ff) + n1;  // convertion binaire sous 32bits
      end;
     
      n2 := '';
      for i := 0 to 3 do
      begin
        n2 := chr((p2 shr (i shl 3)) and $ff) + n2;  // convertion binaire sous 32bits
      end;
     
      result := md5(n1 + n2 + data);
    end;
    En lui même le code est bon, et même après les modifs ça ne marche pas...

    Je pige plus !

    Car pour le format ninaire sur 32bits j'avais pensé a cela:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     SetLength(s, 4);
      Move(p2, s[1], 4);
      data := s + data;
     
      SetLength(s, 4);
      Move(p1, s[1], 4);
      data := s + data;

  13. #13
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 676
    Points : 25 491
    Points
    25 491
    Par défaut
    Citation Envoyé par shadow578 Voir le message
    En lui même le code est bon, et même après les modifs ça ne marche pas...
    Hixie76Signature renvoie une chaine Hexa, tu n'as pas oublié de passer la chaine Hexa en buffer UTF8 via HexToBin ?

    En C++Builder, je te laisse traduire
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
      Hexa = Hixie76Signature(key1, key2, Data);
      Result.SetLength(16);
      HexToBin(Hexa.c_str(), Result.c_str(), 16);


    Sinon, mon code tapé à l'arrache, je l'ai comparé, nous avons tous les deux le même résultat après un HexToBin : IL EST BON !

    Je te conseille d'oublier ton uzinagaz

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for i := 0 to 3 do
      begin
        n1 := chr((p1 shr ((i and 7) shl 3)) and $ff) + n1;  // convertion binaire sous 32bits
      end;
    pour

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
       function SwapLongword(Value: Longword): Longword;
       asm
         BSWAP EAX
       end;




    Citation Envoyé par shadow578 Voir le message
    Car pour le format ninaire sur 32bits j'avais pensé a cela:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     SetLength(s, 4);
      Move(p2, s[1], 4);
      data := s + data;
     
      SetLength(s, 4);
      Move(p1, s[1], 4);
      data := s + data;
    Euh, cela ne fait pas la conversion Little Endian en Big Endian !

  14. #14
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2009
    Messages : 76
    Points : 42
    Points
    42
    Par défaut
    J'ai suivie t'es conseil avec ta fonction par contre je ne comprend pas le:

    Hixie76Signature renvoie une chaine Hexa, tu n'as pas oublié de passer la chaine Hexa en buffer UTF8 via HexToBin ?
    Tu reconvertie en binaire ? Je comprend pas pourquoi :S

  15. #15
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 676
    Points : 25 491
    Points
    25 491
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Result := Result + Format('%.2x', [bHash[i]]);
    La fonction MD5, renvoie une chaine Hexa !
    Il faut remettre cela en binaire !

    Le Protocole WebSockets n'attend pas une chaine Hexa mais une chaine UTF8 je n'ai pas ré-encodé en UTF8 pour obtenir la réponse avec les valeurs d'essai, à vérifier si cela est obligatoire ou pas !?

    Tu trouves que 8jKS'y:G*Co,Wxa- ou fQJ,fN/4F4!~K~MH ressemble à de l'Hexa ?

  16. #16
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2009
    Messages : 76
    Points : 42
    Points
    42
    Par défaut
    Arf je n'arrive pas à le repasser en binaire:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     Hexa = Hixie76Signature(key1, key2, Data);
     SetLength(text, 16);
     HexToBin(Hexa, text, 16);
    Plein d'erreur :o)

  17. #17
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 676
    Points : 25 491
    Points
    25 491
    Par défaut
    Tu plaisantes ?
    Hexa et Text sont des AnsiString, les convertir en PChar, en Delphi 7, c'est simple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    HexToBin(PAnsiChar(Hexa), PAnsiChar(text), 16);
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    HexToBin(@Hexa[1], @text[1], 16);
    Je sais que tu as trouvé le code de la fonction MD5 sur Google puisqu'on la trouve écrite ainsi partout avec string, alors qu'il est tellement plus élégant de l'utiliser avec deux TMemoryStream !
    As-tu essayer de la comprendre en particulier cette ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     pbContent := Pointer(PChar(Input));
    Qui te donnait un exemple de transtypage d'une String en char* (ou PAnsiChar)

  18. #18
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2009
    Messages : 76
    Points : 42
    Points
    42
    Par défaut
    Bien sûr que c'est une fonction que j'ai trouvé

    Bon je te met mon code (qui ne marche toujours pas ) dis moi si tu trouve encore des choses qui vont pas après je te laisse tranquille c'est déjà très sympa

    Moi je continue de chercher de mon côté mais les truc les plus bête je n'y arrive plus je tourne tellement en rond...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
     
    procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    begin
      Memo1.Lines.Add('Connexion du client...');
    end;
     
    procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    var s: string;
    begin
      s := Socket.ReceiveText;
      Memo1.Lines.Add(s);
      envoyerFichier(socket, s);
    end;
     
    procedure TForm1.envoyerFichier(Socket: TCustomWinSocket; nomFichier: String);
    var s: string;
      md5rep: string;
      keyFinal: integer;
     
    begin
      md5rep := decodeEntete(nomFichier);
      SetLength(md5rep, 16);
      keyFinal := HexToBin(@md5rep[1], @text[1], 16);
     
     
     
      s := 'HTTP/1.1 101 WebSocket Protocol Handshake' + #13#10
        +  'Upgrade: WebSocket' + #13#10
        +  'Connection: Upgrade' + #13#10
        +  'Sec-WebSocket-Location: ws://......... + #13#10
        +  'Sec-WebSocket-Origin: http://localhost' + #13#10
        +  'Sec-WebSocket-Protocol: sample' + #13#10
        + #13#10 + md5rep;
     
      Memo1.Lines.Add(s);
      Socket.SendText(s);
    end;
     
     
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Memo1.Clear;
    end;
     
    function TForm1.decodeEntete(s:string):string;
    var i: integer;
      key1, key2, data: string;
    begin
    data := ''; key1 := ''; key2:='';
      For i := 1 to 10 do begin
        if(pos('Sec-WebSocket-Key1: ', Memo1.Lines[i]) > 0) then
          key1 := Memo1.Lines[i]
        else if(pos('Sec-WebSocket-Key2: ', Memo1.Lines[i]) > 0) then
          key2 := Memo1.Lines[i]
        else if(i=9)then data := Memo1.Lines[i];
      end;
     
      key1 := copy(key1, 21, length(key1));
      key2 := copy(key2, 21, length(key2));
     
      Memo1.Lines.Add(#13#10+key1+#13#10+key2+#13#10);
     
      result := Hixie76Signature(key1, key2, data);
     
    end;
     
    function Tform1.Hixie76Signature(key1, key2, data: string): string;
    var s, n1, n2: string;
        i, s1, s2: integer;
        p1, p2: int64;
     
    begin
    s:='';
      result := '';
      s1 := 0;
      s2 := 0;
      n1 := '';
      n2 := '';
     
      for i := 1 to length(key1) do
      begin
        if key1[i] in ['0'..'9'] then
          n1 := n1 + key1[i];
        if (key1[i] = ' ') then
          inc(s1);
      end;
      for i := 1 to length(key2) do
      begin
       if key2[i] in ['0'..'9'] then
          n2 := n2 + key2[i];
        if (key2[i] = ' ') then
          inc(s2);
      end;
     
      p1 := StrToInt64(n1) div s1;
      p2 := StrToInt64(n2) div s2;
     
      n1 := SwapLongword(intToStr(p1));
      n2 := SwapLongword(intToStr(p2));
     
      result := md5(n1 + n2 + data);
    end;
     
    function TForm1.md5(const Input: String): String;
    var
      hCryptProvider: HCRYPTPROV;
      hHash: HCRYPTHASH;
      bHash: array[0..$7f] of Byte;
      dwHashBytes: Cardinal;
      pbContent: PByte;
      i: Integer;
     
    begin
      dwHashBytes := 16;
      pbContent := Pointer(PChar(Input));
     
      Result := '';
     
      if CryptAcquireContext(@hCryptProvider, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT or CRYPT_MACHINE_KEYSET) then
      begin
        if CryptCreateHash(hCryptProvider, CALG_MD5, 0, 0, @hHash) then
        begin
          if CryptHashData(hHash, pbContent, Length(Input) * sizeof(Char), 0) then
          begin
            if CryptGetHashParam(hHash, HP_HASHVAL, @bHash[0], @dwHashBytes, 0) then
            begin
              for i := 0 to dwHashBytes - 1 do
              begin
                Result := Result + Format('%.2x', [bHash[i]]);
              end;
            end;
          end;
          CryptDestroyHash(hHash);
        end;
     
        CryptReleaseContext(hCryptProvider, 0);
      end;
     
      Result := AnsiLowerCase(Result);
    end;
    function TForm1.SwapLongword(Value: string): string;
    asm
      BSWAP EAX
    end;
     
    procedure TForm1.Button2Click(Sender: TObject);
    begin
      ServerSocket1.Open;
      Memo1.Lines.Add('Connexion du serveur...'+#13#10);
    end;
     
    end.

  19. #19
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 676
    Points : 25 491
    Points
    25 491
    Par défaut
    Prend un café bien serré, une bonne inspiration et lit ce que tu as écrit !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    md5rep := decodeEntete(nomFichier);
      SetLength(md5rep, 16);
      keyFinal := HexToBin(@md5rep[1], @text[1], 16);
    md5rep dans ton code fait 32 octets car 16 couple de FF !
    Tu le tronques à 16 ! Tu pers la moitié des données

    Qui est text ?
    Je ne le vois déclarer null part !
    Ne serait-ce pas la Propriété Text de Self, donc de la TForm ???

    Tu n'as pas de violation d'accès en tentant de lire et d'écrire plus que tu ne le devrais ?

    Autre problème !
    SwapLongword dont la fonction est de manipuler un LongWord, tu la modifie pour gérer un String !
    Ne te lance pas dans ce genre de modification d'un code Assembleur que tu ne maitrise pas !
    Là tu ne fais que modifier le pointer du string, j'ose même pas imaginer le résultat !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    function TForm1.SwapLongword(Value: string): string;
    asm
      BSWAP EAX
    end;
    Tu tentes de mélanger mon code avec ton code !
    Mais tu ne respectes ma méthode, cela ne peut pas fonctionner !

    remplace

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
      p1 := StrToInt64(n1) div s1;
      p2 := StrToInt64(n2) div s2;
     
      n1 := SwapLongword(intToStr(p1));
      n2 := SwapLongword(intToStr(p2));
     
      result := md5(n1 + n2 + data);
    par

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      p1 := StrToInt64(n1) div s1;
      p2 := StrToInt64(n2) div s2;
     
      p1 := SwapLongword(p1);
      p2 := SwapLongword(p2);
     
      SetLength(Token, 16);
      CopyMemory(@Token[1], @p1, 4);
      CopyMemory(@Token[5], @p2, 4);
      CopyMemory(@Token[9], @data[1], 8); 
     
     result := md5(Token);
    Token étant un String
    p1 et p2 passe de Int64 à LongWord !

    Sinon pour info, en reprenant ton premier Hixie76Signature, ceci suffisait !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    function Tform1.Hixie76Signature(key1, key2, data: string): string;
    var test, n1, n2, totalKey: string;
        i, s1, s2: integer;
        p1, p2: int64;
     resultHexa: string;
    begin
      result := '';
      s1 := 0;
      n1 := '';
      s2 := 0;
      n2 := '';
      for i := 1 to length(key1) do
      begin
        if ((key1[i] >= '0') and (key1[i] <= '9')) then
          n1 := n1 + key1[i];
        if (key1[i] = ' ') then
          inc(s1);
      end;
      for i := 1 to length(key2) do
      begin
        if ((key2[i] >= '0') and (key2[i] <= '9')) then
          n2 := n2 + key2[i];
        if (key2[i] = ' ') then
          inc(s2);
      end;
      p1 := StrToInt64(n1) div s1;
      p2 := StrToInt64(n2) div s2;
     
      n1 := '';
      for i := 0 to 3 do
      begin
        n1 := chr((p1 shr ((i and 7) shl 3)) and $ff) + n1;  // convertion binaire sous 32bits
      end;
      n2 := '';
      for i := 0 to 3 do
      begin
        n2 := chr((p2 shr ((i and 7) shl 3)) and $ff) + n2;
      end;
     
     
      totalKey := n1 + n2 + UTF8Decode(data);
      resultHexa := md5(totalKey);
     
      // Hexa -> Binaire
      SetLength(Result, 16);
      HexToBin(@resultHexa[1], @Result[1], 16);
     
     
     
    end;

  20. #20
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2009
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2009
    Messages : 76
    Points : 42
    Points
    42
    Par défaut
    Cela devient de plus en plus fouillis mais je veux comprendre jusqu'au bout et que ça marche !

    Bon j'ai repris le code j'ai refait des modifs mais ça bloque avec la fonction SwapLongword je n'arrive pas ...



    OULA ! J'ai fait une modif que j'avais oublier et la j'ai ça compile mais j'ai une violation d'accès :O ?

    D'après le débuggage ça viendrais lorsque je fait :
    CopyMemory(@Token[9], @data[1], 8);

    Réparé mais ça ne marche toujours pas ... niveau serveur..

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. HTML5 : Microsoft propose des modules pour Websocket et IndexedDB
    Par Idelways dans le forum Balisage (X)HTML et validation W3C
    Réponses: 6
    Dernier message: 06/01/2011, 11h18
  2. Réponses: 4
    Dernier message: 22/12/2010, 15h06
  3. Où héberger une application en PHP/HTML5/WebSocket ?
    Par z4k4r14 dans le forum Hébergement
    Réponses: 0
    Dernier message: 21/11/2010, 18h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo