Forum Discussion

abemishler's avatar
abemishler
Visitor
13 years ago

SSL "broke" my channel [SOLVED]

Hello all,

My channel is based on the "videoplayer" example found in the RokuSDK download.

The code to parse a feed is straight forward, yet I am having difficulty getting past the "Can't parse feed" error thrown by:


xml=CreateObject("roXMLElement")
if not xml.Parse(rsp) then
print "Can't parse feed"
return invalid
endif


starting on line 65 of "categoryFeed.brs". This wasn't always the case, however, and I believe I know the reason why. One thing that has changed recently on my server is that we default to serving all content through https. (I have verified the validity of my XML and know for certain the XML itself is not causing the error).

I believe the following line is the reason I can no longer load/parse my feed:

http = NewHttp(conn.UrlCategoryFeed)


Does anyone have experience connecting with https? I've tried searching The Documentation but the search feature doesn't return very useful results. Google doesn't return very useful results either.

I'm hoping to find a method/function I could call similar to:


NewHttps(conn.UrlCategoryFeed)


Thanks in advance,
Abe

edit: marked as [SOLVED] in subject

10 Replies

  • To make a request with SSL, be sure you're setting a certificate file on your roURLTransfer object.

    http://sdkdocs.roku.com/display/sdkdoc/roUrlTransfer

    The URL Transfer object authenticates your web server by calling SetCertificatesFile()with a .pem file that includes the certificate authority cert for the authority (like Verisign, Thawte, etc… or your own with OpenSSL) that signed your web server certificate before making the https request. You can use the Roku standard cert bundle (similar to Mozilla) stored in common:/certs/ca-bundle.crt.
    Your web server can authenticate that the requested connection is from a Roku Streaming Player and that the request is from your application by taking the following actions:

    Add the Roku CA certificate to the web server's certificate authorities keychain. The Roku CA certificate is available in the SDK distribution package, in certs/cacert.pem
    Configure your web server to reject any connection that does not have a valid client certificate.
    Check the X-Roku-Reserved-Dev-Id header in the request. It should contain the Developer ID of your application. If it does not, another application on the Roku is attempting to access the server, so the request should be rejected.

    In order for your web server to perform the steps above to authenticate your Roku Streaming Player, your application needs to call the following functions before performing any https requests:


    Example
    object.SetCertificatesFile("common:/certs/ca-bundle.crt")
    object.AddHeader("X-Roku-Reserved-Dev-Id", "")
    object.InitClientCertificates()
  • Thanks for the reply. Unfortunately, I'm not enough of a brightscript wizard to fully wrap my head around the implementation details. I don't see that I _have_ a "roUrlTransfer" object, and I don't understand what to do with one since it looks like I need an "roXMLElement". So, wondering if "roXMLElement" was a child of "roUrlTransfer" I tried the code pasted below (it didn't work).

    So I'm wondering how to convert/cast? an "roUrlTransfer" object into an "roXMLElement" object? Or, how do I provide the context of a new "roUrlTransfer" object to the "roXMLElement" object that I need to do the parsing?

    Also, at this point, I don't care about validating that the request is coming from my particular application.


    Function load_category_feed(conn As Object) As Dynamic

    '---- putting this here doesn't seem to do anything useful.
    '---- Probably because I'm not using secObj later
    secObj = CreateObject("roUrlTransfer")
    secObj.SetCertificatesFile("common:/certs/ca-bundle.crt")
    secObj.AddHeader("X-Roku-Reserved-Dev-Id", "")
    secObj.InitClientCertificates()

    http = NewHttp(conn.UrlCategoryFeed)

    Dbg("url: ", http.Http.GetUrl())

    m.Timer.Mark()
    rsp = http.GetToStringWithRetry()
    Dbg("Took: ", m.Timer)

    m.Timer.Mark()
    xml=CreateObject("roXMLElement")
    '---- --------------------------------------
    '---- begin failed experiment
    xml.SetCertificatesFile("common:/certs/ca-bundle.crt")
    xml.AddHeader("X-Roku-Reserved-Dev-Id", "")
    xml.InitClientCertificates()
    '---- end failed experiment
    '---- --------------------------------------
    if not xml.Parse(rsp) then
    print "Can't parse feed"
    return invalid
    endif
    Dbg("Parse Took: ", m.Timer)

    ...


    Thanks for reading this far.

    Best,
    Abe
  • It took me a while to figure out the structure of the API documentation. Once I figured out that the actual API calls were available via the links under "Supported Interfaces", I caught on quickly.

    For future devs struggling with this issue, here's what I did. As I mentioned before, my channel is based on the "videoplayer" example. The following code is based on the "categoryFeed.brs" file. You will notice stark similarities upon comparison.

    The following code is great for loading unencrypted resources, but not encrypted resources, so comment it out or delete it.


    Function load_category_feed(conn As Object) As Dynamic

    '** Make an http object to retrieve the unencrypted resource
    'http = NewHttp(conn.UrlCategoryFeed)
    'Dbg("url: ", http.Http.GetUrl())


    I wanted access to an encrypted resource. Here is where setting up the roUrlTransfer object is necessary:


    '** Make the category feed work with an encrypted resource
    https = CreateObject("roUrlTransfer")
    https.SetUrl(conn.UrlCategoryFeed)
    https.SetCertificatesFile("common:/certs/ca-bundle.crt")
    https.AddHeader("X-Roku-Reserved-Dev-Id", "")
    https.InitClientCertificates()


    Then it is quite necessary to use it. Notice the API call is slightly different on the roUrlTransfer object. There is no "GetToStringWithRetry" function, just "GetToString".


    m.Timer.Mark()
    '** The unencrypted response
    'rsp = http.GetToStringWithRetry()
    '** The encrypted response
    rsps = https.GetToString()
    Dbg("Took: ", m.Timer)


    Previously, I overlooked what the roXMLElement was doing. It takes a response as an argument and parses the response. So I changed it to parse my new encrypted response (rsps) instead of the unencrypted response (rsp).


    m.Timer.Mark()
    xml=CreateObject("roXMLElement")
    '** Parse the encrypted response (rsps) or unencrypted response (rsp)
    if not xml.Parse(rsps) then
    print "Can't parse feed"
    return invalid
    endif
    Dbg("Parse Took: ", m.Timer)


    There are other files you will need to modify if you too base your channel on the "videoplayer" example. roPosterScreen objects also support the ifHttpAgent interface. If you load banner ads from an encrypted resource,


    sdAdUrl = "https:// ..."
    hdAdUrl = "https:// ..."
    screen.SetAdUrl(sdAdUrl, hdAdUrl)

    '** Make the screen work with encrypted resources
    screen.SetCertificatesFile("common:/certs/ca-bundle.crt")
    screen.AddHeader("X-Roku-Reserved-Dev-Id", "")
    screen.InitClientCertificates()

    screen.setAdDisplayMode("scale-to-fit")
    screen.Show()


    In total, I made similar changes in categoryFeed.brs, appPosterScreen.brs, appHomeScreen.brs, and showFeed.brs. Hopefully this helps you out if you are currently facing the same questions I was.

    Abe
  • This is great! It helped me get mine working too.

    However, my categories.xml and mychannel.xml contain references to images that are on our HTTPS CDN too.
    You can see our categories.xml on https://air.mozilla.org/roku/categories.xml

    How do you tell Roku about the certs for downloading images on HTTPS?
  • That is sad.
    Does the Roku simply not support any kind of HTTPS for images?
  • destruk's avatar
    destruk
    Streaming Star
    It does if you load the certificate for most all the screens and files - just the gridscreen is a known longstanding bug they haven't tackled yet.
  • Good. So there is hope.

    I'm not sure what the "gridscreen" is to be honest.

    Right now I don't have my Roku device available but when I do I'll sprinkle the code with things like
    screen.SetCertificatesFile("common:/certs/ca-bundle.crt")
    screen.InitClientCertificates()
  • \o/ Yay!

    By adding:

    screen.SetCertificatesFile("common:/certs/ca-bundle.crt")
    screen.InitClientCertificates()

    to the appHomeScreen.brs file fixed it. Now it works.
  • Can you please share your sample file?

    I am not able to figure out which file to edit exactly.

    Thanks