Search Unity

Best HTTP Released

Discussion in 'Assets and Asset Store' started by BestHTTP, Sep 11, 2013.

  1. jtrice

    jtrice

    Joined:
    Aug 29, 2012
    Posts:
    7
    Thanks - I'll slap it in and get back to you.
     
  2. fat_flying_pigs

    fat_flying_pigs

    Joined:
    Feb 3, 2014
    Posts:
    4
    @BestHTTP Thanks for your help so far. I've managed to figure out what the server is expecting. It was broken down to 3 steps:
    1. ssl handshake
    2. message level security: username+password
    3. response

    I believe it looks something like this image: http://i.imgur.com/cxclhCG.jpg

    How would I go about sending my certificate? I see I have received the "server hello" during the ICertificateVerifyer as well as some sort of certificate, but that's as far as I managed to get.
     
  3. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @fat_flying_pigs

    Unfortunately i'm not an SSL/TLS expert, this is why i use a 3rd party solution(BouncyCastle). I'm sure it's possible with BC, but don't know how. I will try to research on this topic tomorrow.
     
  4. jtrice

    jtrice

    Joined:
    Aug 29, 2012
    Posts:
    7
    @BestHTTP -- after your swift response, I'm sorry I took so long to reply.
    Just an update: It looks like I'm having trouble with my servers' CORS config... and I'm clueless about that so I have much research before.

    Works fine for PC/Mac/iOS builds.... yahoo.
    thanks much
     
  5. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @jtrice I would offer my help, but I myself don't have too much experience with CORS, so I can only wish you good luck. :)
     
  6. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @fat_flying_pigs I found something that looks promising, but I had no too much time to check it briefly. Hopefully tomorrow I can do some API changes that you will be able to use to send client certificate to the server.
     
  7. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @fat_flying_pigs Prepared a new package with these changes, but it seems you disabled private messages so i can't send the download link to you.

    With this new package you will be able to write a new class that implements the Org.BouncyCastle.Crypto.Tls.IClientCredentialsProvider interface:
    Code (CSharp):
    1.  
    2. using Org.BouncyCastle.Crypto.Tls;
    3. public sealed class ClientCredentialsProvider : IClientCredentialsProvider
    4. {
    5.     public TlsCredentials GetClientCredentials(TlsContext context, CertificateRequest certificateRequest)
    6.     {
    7.         // TODO: Create and return with a TlsCredentials implementation.
    8.         return null;
    9.     }
    10. }
    11.  
    The TlsCredentials also an interface, according to this SO answer you most probably have to use this implementation:
    Code (CSharp):
    1. using Org.BouncyCastle.Crypto;
    2. using Org.BouncyCastle.Crypto.Tls;
    3. using Org.BouncyCastle.Crypto.Parameters;
    4.  
    5. public class DefaultTlsSignerCredentials : AbstractTlsSignerCredentials
    6. {
    7.     protected readonly TlsContext mContext;
    8.     protected readonly Certificate mCertificate;
    9.     protected readonly AsymmetricKeyParameter mPrivateKey;
    10.     protected readonly SignatureAndHashAlgorithm mSignatureAndHashAlgorithm;
    11.  
    12.     protected readonly TlsSigner mSigner;
    13.  
    14.     public DefaultTlsSignerCredentials(TlsContext context, Certificate certificate, AsymmetricKeyParameter privateKey)
    15.         : this(context, certificate, privateKey, null)
    16.     {
    17.     }
    18.  
    19.     public DefaultTlsSignerCredentials(TlsContext context, Certificate certificate, AsymmetricKeyParameter privateKey,
    20.         SignatureAndHashAlgorithm signatureAndHashAlgorithm)
    21.     {
    22.         if (certificate == null)
    23.             throw new ArgumentNullException("certificate");
    24.         if (certificate.IsEmpty)
    25.             throw new ArgumentException("cannot be empty", "clientCertificate");
    26.         if (privateKey == null)
    27.             throw new ArgumentNullException("privateKey");
    28.         if (!privateKey.IsPrivate)
    29.             throw new ArgumentException("must be private", "privateKey");
    30.         if (TlsUtilities.IsTlsV12(context) && signatureAndHashAlgorithm == null)
    31.             throw new ArgumentException("cannot be null for (D)TLS 1.2+", "signatureAndHashAlgorithm");
    32.  
    33.         if (privateKey is RsaKeyParameters)
    34.         {
    35.             mSigner = new TlsRsaSigner();
    36.         }
    37.         else if (privateKey is DsaPrivateKeyParameters)
    38.         {
    39.             mSigner = new TlsDssSigner();
    40.         }
    41.         else if (privateKey is ECPrivateKeyParameters)
    42.         {
    43.             mSigner = new TlsECDsaSigner();
    44.         }
    45.         else
    46.         {
    47.             throw new ArgumentException("type not supported: " + privateKey.GetType().FullName, "privateKey");
    48.         }
    49.  
    50.         this.mSigner.Init(context);
    51.  
    52.         this.mContext = context;
    53.         this.mCertificate = certificate;
    54.         this.mPrivateKey = privateKey;
    55.         this.mSignatureAndHashAlgorithm = signatureAndHashAlgorithm;
    56.     }
    57.  
    58.     public override Certificate Certificate
    59.     {
    60.         get { return mCertificate; }
    61.     }
    62.  
    63.     /// <exception cref="IOException"></exception>
    64.     public override byte[] GenerateCertificateSignature(byte[] hash)
    65.     {
    66.         try
    67.         {
    68.             if (TlsUtilities.IsTlsV12(mContext))
    69.             {
    70.                 return mSigner.GenerateRawSignature(mSignatureAndHashAlgorithm, mPrivateKey, hash);
    71.             }
    72.             else
    73.             {
    74.                 return mSigner.GenerateRawSignature(mPrivateKey, hash);
    75.             }
    76.         }
    77.         catch (CryptoException e)
    78.         {
    79.             throw new TlsFatalAlert(AlertDescription.internal_error, e);
    80.         }
    81.     }
    82.  
    83.     public override SignatureAndHashAlgorithm SignatureAndHashAlgorithm
    84.     {
    85.         get { return mSignatureAndHashAlgorithm; }
    86.     }
    87. }
    After these steps you can create and set an instance of this class to the request:
    Code (CSharp):
    1.  
    2. var request = new HTTPRequest(new Uri("https://myserver.com"), OnRequestFinished);
    3. request.UseAlternateSSL = true;
    4. request.CustomClientCredentialsProvider = new ClientCredentialsProvider();
    5. request.Send();
    6.  
    Some notes:
    1.) Of course it will work only when UseAlternateSSL is set to true.
    2.) I wasn't able to test it, as doesn't found a server that does client certificate request in the TLS handshake
    3.) You have to find out what form your certificate must be in and what other parameters are you have to pass to the DefaultTlsSignerCredentials constructor.
     
  8. xpxilom

    xpxilom

    Joined:
    Aug 28, 2014
    Posts:
    14
    Last edited: Dec 3, 2015
  9. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @xpxilom

    When you want to send your data encoded with multipart/form-data or application/x-www-form-urlencoded you have to use the AddField or AddBinaryData functions of the request. The plugin by default will choose the most appropriate encoding, but you can force it to use the one that you want.

    So, your code would look more like this:
    Code (CSharp):
    1. HTTPRequest request2 = new HTTPRequest(uri, HTTPMethods.Post, OnRequestFinished);
    2.      
    3. // Add data to our 'form'
    4. request2.AddField("stringField", postData);
    5.  
    6. // Force the plugin to use the multipart/form-data encoding
    7. request2.FormUsage = BestHTTP.Forms.HTTPFormUsage.Multipart;
    8.  
    9. request2.UseAlternateSSL = true;
    10. request2.Send();
    Note that you have to know what 'fieldName' ("stringField" in my example) the server expects.
     
  10. Synergy88-Digital

    Synergy88-Digital

    Joined:
    Sep 9, 2014
    Posts:
    2
    Does this also support WebGL platforms?
     
  11. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @Synergy88 Digital Yes, WebGL builds are supported.
    But, as not all api are available, or the plugin can't access the tcp stream not all features are available(accessing cookies, streaming). And there are other features, that are handled by the browser's implementation (like cookies, caching, proxy handling, etc).
    But, all core features are still supported.
     
    Synergy88-Digital likes this.
  12. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    Latest update (v1.9.5) is out in the Asset Store!

    Relase notes of the update:
    General
    [Fix] The plugin will choose the Content-Length header when Content-Range present too​
    Socket.IO
    [Fix] The plugin will not try to decode the content as chunked, as the browser done it already Socket.IO
    [Fix] Fixed a rare bug where WebSocket transport tried to access a null object​
    WebGL
    [Improvement] Improved threading of HTTPUpdateDelegator WebGL​
    SignalR
    [Improvement] An error event will be emitted on timeout too SignalR
    [Improvement] Call functions now will return true if the plugin was able to send the message to the server​
     
  13. punkouter2019

    punkouter2019

    Joined:
    Jul 28, 2013
    Posts:
    170
    Is this helpful to use with Azure Mobile Apps/REST calls ? Or am I better off just using WWW ?
     
  14. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @punkouter2 Well, if you have no problem using WWW, then you shouldn't buy and use another solution.
     
  15. xpxilom

    xpxilom

    Joined:
    Aug 28, 2014
    Posts:
    14
    @BestHTTP

    Gracias...
     
    Last edited: Dec 3, 2015
  16. zFerz

    zFerz

    Joined:
    Dec 4, 2012
    Posts:
    11
    @BestHTTP
    Hi! We are using your solution not for a long time, but already faced some rare bug.
    1. We call Send method in HTTPRequest class
    2. It starts to call OnRequestFinishedDelegate callback every frame.
    Do you have any similar bugreports? Maybe you fixed this issue in latest release, we did not tested it yet.
     
  17. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @zFerz

    There was a bug that caused an issue like this and already fixed. If you didn't use the latest version of the plugin, you should update it.
     
  18. zFerz

    zFerz

    Joined:
    Dec 4, 2012
    Posts:
    11
    @BestHTTP
    Great news! Thank you so much!!!!1111
     
  19. Synergy88-Digital

    Synergy88-Digital

    Joined:
    Sep 9, 2014
    Posts:
    2
    @BestHTTP

    What API are available?
    currently we are trying to send an API call in JSON format in the WebGL platform.
     
  20. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @Synergy88 Digital

    You can call a web-api with json data like this:

    Code (CSharp):
    1. // The JSon data
    2. string json = "{'field1': 'data1', 'field2': 3.145}";
    3.  
    4. // Create the request
    5. var request = new HTTPRequest(new Uri("http://httpbin.org/post"), HTTPMethods.Post, (req, resp) =>
    6. {
    7.     switch (req.State)
    8.     {
    9.         // The request finished without any problem.
    10.         case HTTPRequestStates.Finished:
    11.             if (resp.IsSuccess)
    12.             {
    13.                 Debug.Log("Request Finished Successfully! Response: " + resp.DataAsText);
    14.             }
    15.             else // Internal server error?
    16.                 Debug.LogWarning(string.Format("Request Finished Successfully, but the server sent an error. Status Code: {0}-{1} Message: {2}",
    17.                                                 resp.StatusCode,
    18.                                                 resp.Message,
    19.                                                 resp.DataAsText));
    20.             break;
    21.  
    22.         // The request finished with an unexpected error. The request's Exception property may contain more info about the error.
    23.         case HTTPRequestStates.Error:
    24.             Debug.LogWarning("Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"));
    25.             break;
    26.  
    27.         // The request aborted, initiated by the user.
    28.         case HTTPRequestStates.Aborted:
    29.             Debug.LogWarning("Request Aborted!");
    30.             break;
    31.  
    32.         // Ceonnecting to the server is timed out.
    33.         case HTTPRequestStates.ConnectionTimedOut:
    34.             Debug.LogError("Connection Timed Out!");
    35.             break;
    36.  
    37.         // The request didn't finished in the given time.
    38.         case HTTPRequestStates.TimedOut:
    39.             Debug.LogError("Processing the request Timed Out!");
    40.             break;
    41.     }
    42. });
    43.  
    44. // Set the Content-Type, we are sending JSon data
    45. request.SetHeader("Content-Type", "application/json; charset=UTF-8");
    46.  
    47. // Convert the JSon data to a byte array
    48. request.RawData = Encoding.UTF8.GetBytes(json);
    49.  
    50. // Send out the request
    51. request.Send();
    This code must work on all supported platforms (including WebGL too).
     
  21. bonty_shushusha

    bonty_shushusha

    Joined:
    Mar 20, 2015
    Posts:
    2
    Hello,

    I use BestHTTP on Unity 5.3. However latest version(v1.9.5) casues error. It seems declaration of ILogger in HTTPManager. And I fix code like below and It seems working. Is this okay?

    Code (CSharp):
    1. // HTTPManager.cs:L138
    2.         /// <summary>
    3.         /// A basic ILogger implementation to be able to log intelligently additional informations about the plugin's internal mechanism.
    4.         /// </summary>
    5.         public static BestHTTP.Logger.ILogger Logger // before: public static ILogger Logger
    6.         {
    7.             get
    8.             {
    9.                 // Make sure that it
    10.                 if (logger == null)
    11.                 {
    12.                     logger = new DefaultLogger();
    13.                     logger.Level = Loglevels.None;
    14.                 }
    15.  
    16.                 return logger;
    17.             }
    18.  
    19.             set { logger = value; }
    20.         }
    21.         private static BestHTTP.Logger.ILogger logger; // before: private static ILogger logger;
     
  22. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @bonty_shushusha

    Unity 5.3 has a new ILogger interface in the UnityEngine namespace that interfere with my interface.
    Already uploaded a new update to the Asset Store, but it's not live yet.In a private message however I sent a download link to you.
    Your fix is good too.
     
    xpxilom likes this.
  23. bonty_shushusha

    bonty_shushusha

    Joined:
    Mar 20, 2015
    Posts:
    2
    @BestHTTP

    Thank you for your response! I'm looking forward to official update :)
     
  24. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    xpxilom likes this.
  25. xpxilom

    xpxilom

    Joined:
    Aug 28, 2014
    Posts:
    14
    BestHTTP Also I have the same problem ...

    You can send MP ???


     
  26. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
  27. Xemenas

    Xemenas

    Joined:
    Sep 10, 2012
    Posts:
    28
    I also upgraded to Unity 5.3 and made the small adjustment to HTTPManager, which fixed that issue but whenever I try to wait for an HTTPRequest in a Coroutine, I get a StackOverflowException (with no other information). Has anyone else experienced this?

    Here's a sample of the send/wait:
    request.Send();
    yield return StartCoroutine(request);

    I know I can change things around to use the callback approach, but I just wanted to check here for a fix / any information first. Thanks for any help!
     
  28. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @Xemenas Sent a download link to an updated package.
     
  29. DimensionU

    DimensionU

    Joined:
    Aug 1, 2013
    Posts:
    43
    Could I also get a download link for the updated package? I'm a paid pro customer. Thanks!
     
  30. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
  31. rxmarccall

    rxmarccall

    Joined:
    Oct 13, 2011
    Posts:
    299
    @BestHTTP

    Also hoping you can send me a link to download package with ILogger fix? Thanks!

    Edit: Got it, thank you!
     
  32. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    rxmarccall likes this.
  33. juuuuun

    juuuuun

    Joined:
    Feb 17, 2014
    Posts:
    23
    Hi, I also have a problem with yield return StartCoroutine(request); with StackOverFlow exception.

    Could you send me a link to an updated package?

    Thank you in advance.
     
  34. rxmarccall

    rxmarccall

    Joined:
    Oct 13, 2011
    Posts:
    299
    @BestHTTP
    I have a JSON file on a server that I want to download locally. I follow your code example that includes creating a request and saving the response to disk, but the saved data is not JSON like I was expecting. Is it possible to download my JSON file to disk just as it exists on the server?
     
  35. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @kongsong You don't have private messages enabled.
     
  36. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @rxmarccall
    Can you send me a repro project? Using the response's Data or DataAsText properties should work just fine.
     
  37. rxmarccall

    rxmarccall

    Joined:
    Oct 13, 2011
    Posts:
    299
    @BestHTTP
    I am able to get the json using the data property of the response, but that is just temporary and passed to the callback function. I'm wanting to know how I can permanently save that json locally so I can access it anytime down the road, and not have to make a HTTP request anytime I want to read it..... I probably am missing something
     
  38. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @rxmarccall
    Well, you can use several solutions for this:
    1. You can save it to a file
    2. You can save it to a static field
    3. You can save it using PlayerPrefs
    And probably there are more options too.
     
  39. rxmarccall

    rxmarccall

    Joined:
    Oct 13, 2011
    Posts:
    299
    @BestHTTP
    So if I wanted to save it to a file, is that something I can natively do in Unity? It isn't related to BestHTTP at all?

    That's what I'm wanting to do, and I'm trying to understand how to actually do it.
     
  40. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @rxmarccall Yes, you can use the classes under the System.IO namespace. They will work on almost all platforms.
     
  41. DudoTheStampede

    DudoTheStampede

    Joined:
    Mar 16, 2015
    Posts:
    55
    I've installed the update (I'm working with Unity 5.3) and tried it but I still get the StackOverflowException error if I use "yield return StartCoroutine(request);". With callback functions no error, but all my code (already tested and working with unity 5.2.X) has StartCoroutine (obviously :p)... I can't get another better error log, I'm using BestHTTP(Basic)!
     
  42. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @DudoTheStampede Yes, it was fixed after I uploaded a new update. But, as this went live yesterday, I will upload a new one with this fix today. Until it will be live, you can use the one I sent to you in a PM.
     
  43. DudoTheStampede

    DudoTheStampede

    Joined:
    Mar 16, 2015
    Posts:
    55
    Thank you! The version you sent me works perfectly!

    One performance related question: do you think is better to use the callback method or the coroutine one? I'm working on an async multiplayer game and I do quite a lot of request!

    Btw, thanks again for the great work!
     
  44. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
  45. xpxilom

    xpxilom

    Joined:
    Aug 28, 2014
    Posts:
    14
    Code (CSharp):
    1. public void Cargar_Foto_De_Perfil()
    2.     {
    3.         string perfil  = "https://graph.facebook.com/"+uid+"/picture?width=9999&height=9999";
    4.         HTTPRequest request = new HTTPRequest(new Uri(perfil), HTTPMethods.Get, (req, resp) =>
    5.             {
    6.                 var tex = new Texture2D(0, 0);
    7.                 tex.LoadImage(resp.Data);
    8.                
    9.                 FOTO_DE_PERFILE.GetComponent<Image>().overrideSprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f));
    10.             });
    11.         request.Send();
    12.  
    13.     }
    I want to load this picture ... a redirect 302 ....

    But it does not work:
    https://graph.facebook.com/100009154388931/picture?width=9999&height=9999

    Any other standard image if it works ...
     
  46. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @xpxilom

    This code worked flawlessly:
    Code (CSharp):
    1. HTTPManager.Logger.Level = BestHTTP.Logger.Loglevels.All;
    2.  
    3. Uri uri = new Uri("https://graph.facebook.com/100009154388931/picture?width=9999&height=9999");
    4.  
    5. HTTPRequest request = new HTTPRequest(uri, (req, resp) =>
    6. {
    7.     switch (req.State)
    8.     {
    9.         // The request finished without any problem.
    10.         case HTTPRequestStates.Finished:
    11.             if (resp.IsSuccess)
    12.             {
    13.                 Debug.Log("Request Finished Successfully! " + resp.Data.Length);
    14.             }
    15.             else // Internal server error?
    16.                 Debug.LogWarning(string.Format("Request Finished Successfully, but the server sent an error. Status Code: {0}-{1} Message: {2}",
    17.                                                 resp.StatusCode,
    18.                                                 resp.Message,
    19.                                                 resp.DataAsText));
    20.             break;
    21.  
    22.         // The request finished with an unexpected error. The request's Exception property may contain more info about the error.
    23.         case HTTPRequestStates.Error:
    24.             Debug.LogWarning("Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"));
    25.             break;
    26.  
    27.         // The request aborted, initiated by the user.
    28.         case HTTPRequestStates.Aborted:
    29.             Debug.LogWarning("Request Aborted!");
    30.             break;
    31.  
    32.         // Ceonnecting to the server is timed out.
    33.         case HTTPRequestStates.ConnectionTimedOut:
    34.             Debug.LogError("Connection Timed Out!");
    35.             break;
    36.  
    37.         // The request didn't finished in the given time.
    38.         case HTTPRequestStates.TimedOut:
    39.             Debug.LogError("Processing the request Timed Out!");
    40.             break;
    41.     }
    42. });
    43.  
    44. request.Send();
    And produced the following logs:
     
  47. Icaro-Malta

    Icaro-Malta

    Joined:
    Jan 21, 2013
    Posts:
    5
    @BestHTTP
    I'm getting StackOverflowException too. Can you send me this fixed version too?
     
  48. xpxilom

    xpxilom

    Joined:
    Aug 28, 2014
    Posts:
    14
    Last edited: Dec 12, 2015
  49. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
  50. BestHTTP

    BestHTTP

    Joined:
    Sep 11, 2013
    Posts:
    1,336
    @xpxilom


    Well, you can set the request's MaxRedirects property to 0, then in the callback you can get the "location" header from the response. Then you can do a new request for this new url.