Données via URL

20:35 modifié dans API AppKit #1
Bonjour,

j'aimerai pouvoir envoyer une donnée puis la récupérer via une URL.
Le problème est que je n'arrive pas récupérer le NSData de l'URL.
Par exemple :
test://< 04bc58de 04bc58de 04bc58de 04bc58de >
Et j'aimerai récupérer "< 04bc58de 04bc58de 04bc58de 04bc58de >" qui est la donnée (NSData)
Je sais pas si ça se fait mais bon.. ça serait cool.

En fait mon application permet de créer des dossiers persos (NSDictionary), donc j'aimerai bien inclure une sorte de partage de dossiers via URL.

Réponses

  • schlumschlum Membre
    20:35 modifié #2
    Rien compris  :P
  • 20:35 modifié #3
    Bon je m'explique un peu mieux.

    Dans mon application, l'utilisateur peut créer des dossiers personnalisés (dans l'application). Le truc ça sera de pouvoir partager ses dossiers via une simple URL générée par mon application.

    Chaque dossier est un NSDictionary. Donc quand je choisis de partager le dossier, l'application me donnerait une url comme ceci : "MonApplication://DONNEES_DU_NSDICTIONARY"

    Lorsque l'utilisateur cliquera sur ce lien, mon application s'ouvre, et là  je décode "DONNEES_DU_NSDICTIONARY" pour ensuite ajouter le dossier à  sa liste.
  • AliGatorAliGator Membre, Modérateur
    20:35 modifié #4
    Le problème c'est que tel que tu formattes ton URL, ce n'est pas une URL au sens des RFC 1808, 2396 & co.
    Je ne suis pas persuadé que ton approche soit la bonne, mais bon j'imagine que tu ne peux pas simplement donner des identifiants à  tes dossiers virtuels, le but étant de les partager entre ordinateurs différents, et que l'URL "explique" en tout point à  ton application comment créer le dossier virtuel et son contenu...

    Il faut donc que tu sérialises tes données de manière à  obtenir une chaà®ne de caractères qui respecte la RFC 2396 entre autres, pour pouvoir utiliser cette chaà®ne comme une URL.
    Le plus simple est d'obtenir une représentation en NSData de ton dictionnaire, puis d'exprimer cette représentation en hexadécimal, pour être sûr de ne pas avoir d'espace ni de caractère invalide, et de construire alors ton URL du genre [tt]monApplication://createFolder/04ae7fd3c7e6db8a...[/tt]
    Note que la façon dont tu l'as noté plus haut, même si ça ressemble à  un encodage hexadecimal, ce n'est que le [tt]description[/tt] de ton NSData... qui contient "<NSData" et ">" en trop, et surtout plein d'espaces

    Mais le risque c'est alors de voir tes NSData, une fois représentés en hexadécimal, dépasser la longueur max des URL (256 caractères, je crois ?)

    Et de toute façon il y a des chances que tu te heurtes à  ce problème de taille maxi des URLs. Même si tu utilises une autre sérialisation, tu trouveras toujours des NSData qui, une fois sérialisées en des caractères se conformant à  la RFC 2396 de syntaxe des URLs, risquent de dépasser la taille max.

    Donc faut peut-être se reposer la question de la faisabilité de la chose... déjà  pour créer une URL valide. Parce que sans URL valide, point de décodage d'URL ensuite et donc point de récupération des NSData reconstruites après désérialisation de l'URL ;)
  • TchouboudouTchouboudou Membre
    20:35 modifié #5
    Je sais pas si c'est réalisable dans ce cas là , mais Bonjour pourrait servir, non ?
  • schlumschlum Membre
    20:35 modifié #6
    En gros, tu veux faire un protocole où tu passes toutes les données dans l'URL... Pas vraiment réalisable je pense... Comme dit AliGator, tu vas vite exploser les tailles max !
    Par contre, tu peux le faire à  la GET : test://addr?v=<data>
  • 20:35 modifié #7
    Yop,

    Je pense avoir trouvé une solution pour mon Application.
    Le plus important pour un dossier perso c'est le nom et ce qu'il contient.
    Mon application, vous la connaissez sûrement déjà , permet de référencer des freewares pour Mac OS X et de les faire découvrir aux utilisateurs.
    Donc il y a une Array qui contient les applications choisis par l'utilisateur dans chaque dossier.

    Donc en gros :

    {
    <key>Name</key>
    <string>LeNom</key>
    <key>Applications</key>
        <array>
              <string>App1</string> 
              <string>App2</string>
              <string>App3</string>
              <string>App4</string>
        </array>
    }
    (On s'en fiche si ma représentation est pas bonne, c'est pour que vous compreniez mieux comment c'est foutu).
    L'avantage est que je fonctionne aussi par ID de logiciels.

    Dans ce cas je pourrais peut-être envoyé l'URL comme ceci :
    MonApp://LeNom/ID1.ID2.ID3.ID4...

    Pour les URLs, je ne savait pas qu'elles étaient limitées, du moins j'y avais jamais vraiment pensé. Mais dans ce cas, si elles sont limitées à  256 caractères comme tu le dis Alli, je peux proposer à  l'utilisateur d'enregistrer le groupe sous forme d'un fichier à  envoyer aux ami(es) dans ce cas là .

    J'autorise aussi la création de dossiers intelligents, qui font donc un trie automatique de tous les logiciels de la base de données en fonction des critères choisis.
    Et dans ce cas là  je pourrais faire :
    MonApp://LeNomDuSmartGroup/Option1:critere1.critere2.critere3/Option2.......
    On peut créer 5 options maximales et pareil, si ça dépasse 256 caractères je propose d'enregistrer dans un fichier.

  • laurrislaurris Membre
    20:35 modifié #8
    dans 1195400113:


    Lorsque l'utilisateur cliquera sur ce lien, mon application s'ouvre, et là  je décode "DONNEES_DU_NSDICTIONARY" pour ensuite ajouter le dossier à  sa liste.



    C'est carrément possible puisque je l'ai déjà  fait. Il faut utiliser les AppleEvents et enregistrer ton appli pour qu'elle ouvre les url commençant par test://

    1. Dans le awakeFromNib du delegate de NSApplication:

    <br /> [[ NSAppleEventManager sharedAppleEventManager ]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;setEventHandler: self<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;andSelector: @selector(getUrl:withReplyEvent:)<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;forEventClass: kInternetEventClass<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; andEventID: kAEGetURL ];<br />
    


    2. Dans le même delegate:

    <br />- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;<br />{<br />&nbsp; NSString *rawurl = [[ event paramDescriptorForKeyword: keyDirectObject ] stringValue ];<br /> <br />// rawurl c&#39;est le string de l&#39;url test://&lt;data bidule&gt;. Plus qu&#39;à  parser et bosser avec le &lt;data bidule&gt;<br />}<br />
    

    3. Dans le Info.plist , ajouter ceci pour qu'un clic sur l'URL ouvre ton appli:

    <br />	&lt;key&gt;CFBundleURLTypes&lt;/key&gt;<br />	&lt;array&gt;<br />		&lt;dict&gt;<br />			&lt;key&gt;CFBundleURLSchemes&lt;/key&gt;<br />			&lt;array&gt;<br />				&lt;string&gt;test&lt;/string&gt;<br />			&lt;/array&gt;<br />		&lt;/dict&gt;<br />	&lt;/array&gt;<br />
    


    4. Quand c'est prêt, annoncer la mise à  jour à  tous ceux qui pensaient kecépapossibe !
  • 20:35 modifié #9
    ça c'est prêt depuis un bon moment, sauf que le data impossible à  récupérer :D
  • laurrislaurris Membre
    20:35 modifié #10
    Ah bon , alors je comprends pas bien le problème. Qu'est-ce qui coince ? le formatage de l'url , la limite de 256 charactères ?
  • BruBru Membre
    20:35 modifié #11
    Je pense avoir compris...

    Tu transformes ton NSDictionary en NSData.
    Ce NSData te sert (du moins sa représentation) d'url.
    Ensuite, quand ton appli reçoit l'appel de l'url, tu veux récupérer l'adresse pour la retransformer en NSData puis NSDictionary.

    Est ce ça ?

    Quant à  la taille d'une url, cela varie en fait en fonction du client.
    Formellement, la taille est de 1024. Mais il est conseillé de ne pas dépasser les 255 car certains vieux clients ne pourraient pas traiter ce qui se trouve au delà . Pourtant les navigateurs récents proposent plus.

    .
  • 20:35 modifié #12
    dans 1195424191:

    Je pense avoir compris...

    Tu transformes ton NSDictionary en NSData.
    Ce NSData te sert (du moins sa représentation) d'url.
    Ensuite, quand ton appli reçoit l'appel de l'url, tu veux récupérer l'adresse pour la retransformer en NSData puis NSDictionary.

    Est ce ça ?

    Quant à  la taille d'une url, cela varie en fait en fonction du client.
    Formellement, la taille est de 1024. Mais il est conseillé de ne pas dépasser les 255 car certains vieux clients ne pourraient pas traiter ce qui se trouve au delà . Pourtant les navigateurs récents proposent plus.

    .


    C'est exactement ce que je veux faire. Tout comme l'a suggéré Laurris. C'est ce que j'avais fait au départ.
    En fait Laurris, pour reprendre ce que je disais, ça ne marche pas car en fait lorsque je récupère la représentation d'un NSData, j'obtiens bien < eD9b14cf etc.... >
    Pour en faire une URL disons "correcte" je dois eviter les espace. Donc au lieu d'utiliser "stringByAddingPercentEspacesUsingEncoding:" j'ai choisis d'analyser mon URL avec espace et de les enlever.
    Ainsi ça donnait : xtastes://eD9b14cfetc....
    Quand je récupère l'URL, je la reformate et j'obtiens bien < eD9b14cf etc... > comme au départ.
    Sauf que évidemment, ça peut pas être aussi simple que ça et impossible de dire que ce que je récupère est un NSData. Donc NSDictionary* group = [NSUnarchiver unarchiveObjectWithData:LeDataReformaté]; ne marche pas
  • schlumschlum Membre
    20:35 modifié #13
    Pourquoi ne pas faire une catégorie de NSData qui ferait de l'export / import MIME ?
  • 20:35 modifié #14
    Ben déjà  je sais pas comment x.x et je me demande si ma solution est pas plus simple au final. Faut que je réfléchisse un peu a ça :s
  • laurrislaurris Membre
    20:35 modifié #15
    dans 1195425599:

    Sauf que évidemment, ça peut pas être aussi simple que ça et impossible de dire que ce que je récupère est un NSData. Donc NSDictionary* group = [NSUnarchiver unarchiveObjectWithData:LeDataReformaté]; ne marche pas


    En fait ta question n'a rien à  voir avec les url ou la façon de les traiter. C'est comment faire pour encoder/decoder un NSData en NSString. Sur ce point de plus experts que moi pourront te répondre.
    Mais je ne saisis pas pourquoi tu n'utilise pas stringByAddingPercentEspacesUsingEncoding: sur la description du dictionary. Ensuite dans le handler tu décodes l'URL en string > data > dictionary.

    A mon avis la limitation de 256 n'a pas de sens dans ton cas puisque le navigateur n'interprète pas l'url, il la passe direct à  l' NSAppleEventManager. Script Editor a dans 10.4 la possibilité d'ouvrir des scripts à  partir d'URL et la longueur des scripts atteint plus de 256 char sans problème.
  • 20:35 modifié #16
    dans 1195428232:

    dans 1195425599:

    Sauf que évidemment, ça peut pas être aussi simple que ça et impossible de dire que ce que je récupère est un NSData. Donc NSDictionary* group = [NSUnarchiver unarchiveObjectWithData:LeDataReformaté]; ne marche pas


    En fait ta question n'a rien à  voir avec les url ou la façon de les traiter. C'est comment faire pour encoder/decoder un NSData en NSString. Sur ce point de plus experts que moi pourront te répondre.

    C'est tout à  fait ce à  quoi j'ai pensé !
    Et donc ce que je n'ai pas réussi à  faire malgré toute une après midi passé dessus.
  • schlumschlum Membre
    20:35 modifié #17
    Ben c'est pour ça que je te disais de faire une catégorie de NSData... Bon, le MIME c'est peut-être un poil complexe, mais faire une méthode qui transforme en string hexa et une autre qui fait l'inverse c'est pas sorcier.
  • AliGatorAliGator Membre, Modérateur
    20:35 modifié #18
    Alors pendant qu'on y est, plutôt que d'utiliser l'encodage Hexa, où chaque octet est représenté par 2 caractères (comme "e9" pour l'octet de valeur 233), il peut être judicieux d'utiliser l'encodage base64, qui ne multiplie que par 4/3 la taille des données originales, tout en ayant la même propriété que l'encodage hexa, à  savoir n'être constitué que de caractères imprimables ("A-Z","a-z","0-9","+","/","=") qui sont acceptés dans les URL.
    Comme ça un NSData de longueur 30 qui auraà®t nécessité 60 caractères pour être représenté en hexa, ne nécessitera que 40 caractères dans sa représentation base64. :)

    Donc en somme ce que je te conseille, c'est de créer une catégorie de NSData qui va te rajouter la méthode [tt]NSString * encodeBase64[/tt] et une catégorie de NSString qui va te rajouter la méthode [tt]NSData * decodeBase64[/tt]. Ainsi tu pourras, à  partir de ton NSData (représentation sérialisée de ton NSDictionary), obtenir une NSString (représentation en base64 de tes données) et l'utiliser dans ton URL, et dans l'autre sens lors de la récupération de l'URL, tu pourras retransformer ton NSString en NSData (puis en NSDictionary ou ce que tu veux).


    Pour encoder/décoder en base64, tu peux utiliser libcrypto (OpenSSL) qui contient des méthodes pour faire ça, ça t'évitera de tout recoder. Le code a déjà  été pondu sur CocoaDev : regarde vers la fin quand ils proposent d'utiliser libssl directement ("You can using libcrypto, part of OpenSSL, to do this directly without spawning a task:")
    En plus c'est mieux que la représentation hexa car d'une part ça prend moins de place une fois encodé, mais en plus le code est déjà  tout fait :P alors que pour la représentation hexa sinon tu vas devoir la faire toi-même (ceci dit entre nous c'est pas sorcier comme dit schlum)
  • 20:35 modifié #19
    Elles sont excitantes ces lignes de code ! Je regarde ça desuite !  Merci à  vous
  • novembre 2007 modifié #20
    Bon ben ça marche, même si le code encodage/décodage je le comprend pas... ça utilise des trucs du genre "BIO" que je comprend pas.
    En tout cas j'ai tout vérifié, ça marche très bien et j'obtiens bien mon dossier décodé au final :
    <br />2007-11-19 22:00:54.395 XTastes[1728:10b] {<br />&nbsp; &nbsp; Applications =&nbsp; &nbsp; &nbsp;(<br />&nbsp; &nbsp; &nbsp; &nbsp; Adium,<br />&nbsp; &nbsp; &nbsp; &nbsp; FStream,<br />&nbsp; &nbsp; &nbsp; &nbsp; &quot;MacFreeware Update&quot;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &quot;Resize &#39;Em All&quot;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &quot;SNCF Schedules&quot;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &quot;TotalTunes Control&quot;<br />&nbsp; &nbsp; );<br />&nbsp; &nbsp; Contents = 6;<br />&nbsp; &nbsp; Enable = 1;<br />&nbsp; &nbsp; Image = FNew;<br />&nbsp; &nbsp; Name = Favorites;<br />}<br />
    


    Si ça en branche quelques uns je pourrai en faire un framework et le mettre sur les ressources d'Objective-Cocoa ?

    Petite remarque, j'ai du utiliser
    <br /> BIO * mem = BIO_new_mem_buf((void *) [self UTF8String], [self lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);<br />
    

    à  la place de
    <br /> BIO * mem = BIO_new_mem_buf((void *) [self cString], [self cStringLength]);<br />
    

    car "deprecated in Mac OS X 10.4".
    Mon appli sera Leopard uniquement donc ça va ^^
  • AliGatorAliGator Membre, Modérateur
    novembre 2007 modifié #21
    Ouah c'est cool si ça marche alors :up:

    C'est pas un drame d'utiliser la UTF8String au lieu de la cString, vu que ce que tu récupères ce sont des caractères qui sont normalement le résultat d'un encodage Base64 : donc ils ne contiennent que [A-Za-z0-9/+=] qui sont des caractères ASCII-7bits : autrement dit ils ont la même représentation en UTF8 qu'en "caractères (octets) bruts".

    Sinon pour ton information BIO ça n'a rien à  voir avec l'agriculture biologique :) mais ce sont des structures utilisées en OpenSSL pour faire de l'abstraction sur les entrées/sorties, d'où le "IO" (Input/Output) de "BIO". Ce qui est fort avec ce mécanisme, c'est qu'on peut créer un BIO à  partir d'un fichier ou d'une zone mémoire (ici c'est notre cas) ou un socket réseau ou autre, ça s'utilise pareil... Mais surtout ensuite on peut créer une chaà®ne de filtres (BIO_f_...) qui vont filtrer les données lues et/ou écrites de manière transparente.
    Du coup tu construit une "chaà®ne BIO" qui inclut un filtre base64 et automatiquement ça va encoder en base64 lors de la lecture, décoder lors de l'écriture, et ce de façon transparente...

    Enfin bref, même si ça semble bizarroà¯de comme code au premier abord, au final c'est assez bien foutu (pour du code C donc non encapsulé objet :P). Juste pour ta culture : la page man qui va bien ;D


    Oh, et petite précision, dans le lien vers CocoaDev ils proposent de rajouter 2 méthodes, une avec un paramètre et l'autre sans. par défaut la valeur du paramètre est à  YES, ce qui fait qu'il rajoute des sauts de ligne régulièrement dans le résultat de l'encodage base64.
    Ceci est pratique si tu veux encoder un long fichier (par exemple du genre le mode "uuencode") en base64 pour le formatter*, mais dans ton cas, à  savoir pour l'utiliser dans une URL, c'est évidemment à  proscrire : il faut bien sûr passer NO comme paramètre ! :o

    *pour la petite histoire, c'est surtout historique, je me rappelle du format uuencode utilisé pour l'envoi de pièces jointes par mail/newgroups, où les données binaires (les fichiers en PJ) étaient envoyées sous forme uuencodée, c-à -d encodées en base64 puis envoyées comme du texte normal dans le mail... ou comment envoyer des fichiers via un système prévu à  l'origine uniquement pour le texte :)
  • 20:35 modifié #22
    Merci pour les précisions Ali !
    J'avais bien mis NO pour les espaces :D ça au moins j'avais compris  ;D
Connectez-vous ou Inscrivez-vous pour répondre.