content: '**********************************************************
  '**  Video Player Example Application - URL Utilities 
  '**  November 2009
  '**  Copyright (c) 2009 Roku Inc. All Rights Reserved.
  '**********************************************************
  
  REM ******************************************************
  REM Constucts a URL Transfer object
  REM ******************************************************
  
  Function CreateURLTransferObject(url As String) as Object
      obj = CreateObject("roUrlTransfer")
      obj.SetPort(CreateObject("roMessagePort"))
      obj.SetUrl(url)
      obj.AddHeader("Content-Type", "application/x-www-form-urlencoded")
      obj.EnableEncodings(true)
      return obj
  End Function
  
  REM ******************************************************
  REM Url Query builder
  REM so this is a quick and dirty name/value encoder/accumulator
  REM ******************************************************
  
  Function NewHttp(url As String) as Object
      obj = CreateObject("roAssociativeArray")
      obj.Http                        = CreateURLTransferObject(url)
      obj.FirstParam                  = true
      obj.AddParam                    = http_add_param
      obj.AddRawQuery                 = http_add_raw_query
      obj.GetToStringWithRetry        = http_get_to_string_with_retry
      obj.PrepareUrlForQuery          = http_prepare_url_for_query
      obj.GetToStringWithTimeout      = http_get_to_string_with_timeout
      obj.PostFromStringWithTimeout   = http_post_from_string_with_timeout
  
      if Instr(1, url, "?") > 0 then obj.FirstParam = false
  
      return obj
  End Function
  
  
  REM ******************************************************
  REM Constucts a URL Transfer object 2
  REM ******************************************************
  
  Function CreateURLTransferObject2(url As String, contentHeader As String) as Object
      obj = CreateObject("roUrlTransfer")
      obj.SetPort(CreateObject("roMessagePort"))
      obj.SetUrl(url)
      obj.AddHeader("Content-Type", contentHeader)
      obj.EnableEncodings(true)
      return obj
  End Function
  
  REM ******************************************************
  REM Url Query builder 2
  REM so this is a quick and dirty name/value encoder/accumulator
  REM ******************************************************
  
  Function NewHttp2(url As String, contentHeader As String) as Object
      obj = CreateObject("roAssociativeArray")
      obj.Http                        = CreateURLTransferObject2(url, contentHeader)
      obj.FirstParam                  = true
      obj.AddParam                    = http_add_param
      obj.AddRawQuery                 = http_add_raw_query
      obj.GetToStringWithRetry        = http_get_to_string_with_retry
      obj.PrepareUrlForQuery          = http_prepare_url_for_query
      obj.GetToStringWithTimeout      = http_get_to_string_with_timeout
      obj.PostFromStringWithTimeout   = http_post_from_string_with_timeout
  
      if Instr(1, url, "?") > 0 then obj.FirstParam = false
  
      return obj
  End Function
  
  
  REM ******************************************************
  REM HttpEncode - just encode a string
  REM ******************************************************
  
  Function HttpEncode(str As String) As String
      o = CreateObject("roUrlTransfer")
      return o.Escape(str)
  End Function
  
  REM ******************************************************
  REM Prepare the current url for adding query parameters
  REM Automatically add a '?' or '&' as necessary
  REM ******************************************************
  
  Function http_prepare_url_for_query() As String
      url = m.Http.GetUrl()
      if m.FirstParam then
          url = url + "?"
          m.FirstParam = false
      else
          url = url + "&"
      endif
      m.Http.SetUrl(url)
      return url
  End Function
  
  REM ******************************************************
  REM Percent encode a name/value parameter pair and add the
  REM the query portion of the current url
  REM Automatically add a '?' or '&' as necessary
  REM Prevent duplicate parameters
  REM ******************************************************
  
  Function http_add_param(name As String, val As String) as Void
      q = m.Http.Escape(name)
      q = q + "="
      url = m.Http.GetUrl()
      if Instr(1, url, q) > 0 return    'Parameter already present
      q = q + m.Http.Escape(val)
      m.AddRawQuery(q)
  End Function
  
  REM ******************************************************
  REM Tack a raw query string onto the end of the current url
  REM Automatically add a '?' or '&' as necessary
  REM ******************************************************
  
  Function http_add_raw_query(query As String) as Void
      url = m.PrepareUrlForQuery()
      url = url + query
      m.Http.SetUrl(url)
  End Function
  
  REM ******************************************************
  REM Performs Http.AsyncGetToString() in a retry loop
  REM with exponential backoff. To the outside
  REM world this appears as a synchronous API.
  REM ******************************************************
  
  Function http_get_to_string_with_retry() as String
      timeout%         = 1500
      num_retries%     = 5
  
      str = ""
      while num_retries% > 0
  '        print "httpget try " + itostr(num_retries%)
          if (m.Http.AsyncGetToString())
              event = wait(timeout%, m.Http.GetPort())
              if type(event) = "roUrlEvent"
                  str = event.GetString()
                  exit while
              elseif event = invalid
                  m.Http.AsyncCancel()
                  REM reset the connection on timeouts
                  m.Http = CreateURLTransferObject(m.Http.GetUrl())
                  timeout% = 2 * timeout%
              else
                  print "roUrlTransfer::AsyncGetToString(): unknown event"
              endif
          endif
  
          num_retries% = num_retries% - 1
      end while
      
      return str
  End Function
  
  REM ******************************************************
  REM Performs Http.AsyncGetToString() with a single timeout in seconds
  REM To the outside world this appears as a synchronous API.
  REM ******************************************************
  
  Function http_get_to_string_with_timeout(seconds as Integer) as String
      timeout% = 1000 * seconds
  
      str = ""
      m.Http.EnableFreshConnection(true) 'Don't reuse existing connections
      if (m.Http.AsyncGetToString())
          event = wait(timeout%, m.Http.GetPort())
          if type(event) = "roUrlEvent"
              str = event.GetString()
          elseif event = invalid
              Dbg("AsyncGetToString timeout")
              m.Http.AsyncCancel()
          else
              Dbg("AsyncGetToString unknown event", event)
          endif
      endif
  
      return str
  End Function
  
  REM ******************************************************
  REM Performs Http.AsyncPostFromString() with a single timeout in seconds
  REM To the outside world this appears as a synchronous API.
  REM ******************************************************
  
  Function http_post_from_string_with_timeout(val As String, seconds as Integer) as String
      timeout% = 1000 * seconds
  
      str = ""
  '    m.Http.EnableFreshConnection(true) 'Don't reuse existing connections
      if (m.Http.AsyncPostFromString(val))
          event = wait(timeout%, m.Http.GetPort())
          if type(event) = "roUrlEvent"
              print "1"
              str = event.GetString()
          elseif event = invalid
              print "2"
              Dbg("AsyncPostFromString timeout")
              m.Http.AsyncCancel()
          else
              print "3"
              Dbg("AsyncPostFromString unknown event", event)
          endif
      endif
  
      return str
  End Function
  
  ' ********************************************************************
  ' ** Get a HTML page with timeout. Gather up error info and return it
  ' ********************************************************************
  Function getHTMLWithTimeout(url As String, seconds As Integer) as Object
      timeout% = 1000 * seconds
  
      result = { str : "", error : false, response : 0, reason : "" }
  
      http = CreateObject("roUrlTransfer")
      http.SetUrl(url)
      http.SetPort(CreateObject("roMessagePort"))
      http.EnableFreshConnection(true) 'Don't reuse existing connections
      if (http.AsyncGetToString())
          event = wait(timeout%, http.GetPort())
          if type(event) = "roUrlEvent"
              if event.GetResponseCode() = 200 then
                  result.str = event.GetString()
              else
                  result.error = true
                  result.response = event.GetResponseCode()
                  result.reason = event.GetFailureReason()
              end if
          elseif event = invalid
              Dbg("AsyncGetToString timeout")
              http.AsyncCancel()
          else
              Dbg("AsyncGetToString unknown event", event)
          endif
      endif
  
  '    print "HTTP result: "
  '    print result
  
      return result
  End Function
  
  ' ********************************************************************
  ' POST a value to a URL and get the response
  ' ********************************************************************
  Function postHTMLWithTimeout(url As String, content As String, seconds As Integer) as Object
      timeout% = 1000 * seconds
  
      result = { str : "", error : false, response : 0, reason : "" }
  
      http = CreateObject("roUrlTransfer")
      http.SetUrl(url)
      http.SetPort(CreateObject("roMessagePort"))
      http.EnableFreshConnection(true) 'Don't reuse existing connections
      if (http.AsyncPostFromString(content))
          event = wait(timeout%, http.GetPort())
          if type(event) = "roUrlEvent"
              if event.GetResponseCode() = 200 then
                  result.str = event.GetString()
              else
                  result.error = true
                  result.response = event.GetResponseCode()
                  result.reason = event.GetFailureReason()
              end if
          elseif event = invalid
              Dbg("AsyncGetToString timeout")
              http.AsyncCancel()
          else
              Dbg("AsyncGetToString unknown event", event)
          endif
      endif
  
  '    print "HTTP result: "
  '    print result
  
      return result
  End Function
  