-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUrlUtils.brs
352 lines (274 loc) · 11 KB
/
UrlUtils.brs
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
'**********************************************************
'** Emby Roku Client - URL Utilities
'**********************************************************
'**********************************************************
'** Video Player Example Application - URL Utilities
'** November 2009
'** Copyright (c) 2009 Roku Inc. All Rights Reserved.
'**********************************************************
'**********************************************************
'** Add to Query Array
'**********************************************************
Function AddToQuery(query As Object, fields As Object) As Object
for each key in fields
query.AddReplace(key, fields[key])
end for
return query
End Function
'**********************************************************
'** HTTP Encode a String
'**********************************************************
Function HttpEncode(str As String) As String
obj= CreateObject("roUrlTransfer")
return obj.Escape(str)
End Function
'**********************************************************
'** Create HTTP Request
'**********************************************************
Function HttpRequest(url As String) as Object
obj = CreateObject("roAssociativeArray")
obj.Http = CreateURLTransferObject(url)
obj.ContentType = http_content_type
obj.AddAuthorization = http_authorization
obj.GetUrl = http_get_url
obj.GetRequest = http_get_request
obj.SetRequest = http_set_request
obj.FirstParam = true
obj.CountParams = 0
obj.AddParam = http_add_param
obj.UpdateParam = http_update_param
obj.RemoveParam = http_remove_param
obj.BuildQuery = http_build_query
obj.AddRawQuery = http_add_raw_query
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
r = CreateObject("roRegex", "&", "")
obj.CountParams = r.Split(url).Count()
obj.FirstParam = false
end if
return obj
End Function
Function http_get_request() As Object
return m.Http
End Function
'**********************************************************
'** Creates URL Transfer Object
'**********************************************************
Function CreateURLTransferObject(url As String) as Object
obj = CreateObject("roUrlTransfer")
obj.SetPort(CreateObject("roMessagePort"))
obj.SetUrl(url)
obj.EnableEncodings(true)
if url.instr("https") > -1 then
obj.SetCertificatesFile("common:/certs/ca-bundle.crt")
obj.InitClientCertificates()
end if
return obj
End Function
'**********************************************************
'** Add a Content-Type Header
'**********************************************************
Function http_content_type(contentType As String) As Void
if contentType = "json"
m.Http.AddHeader("Content-Type", "application/json")
else
' Fallback to standard content type
m.Http.AddHeader("Content-Type", "application/x-www-form-urlencoded")
end if
End Function
'**********************************************************
'** Add a Authorization Header
'**********************************************************
Function http_authorization() As Void
authString = "MediaBrowser"
authString = authString + " Client=" + Quote() + "Roku" + Quote()
authString = authString + ", Device=" + Quote() + firstOf(regRead("prefDisplayName"), getGlobalVar("rokuModelName", "Unknown")) + Quote()
authString = authString + ", DeviceId=" + Quote() + getGlobalVar("rokuUniqueId", "Unknown") + Quote()
authString = authString + ", Version=" + Quote() + HttpEncode(getGlobalVar("channelVersion", "Unknown")) + Quote()
if getGlobalVar("user") <> invalid
authString = authString + ", UserId=" + Quote() + HttpEncode(getGlobalVar("user").Id) + Quote()
end if
m.Http.AddHeader("X-Emby-Authorization", authString)
activeServerId = RegRead("currentServerId")
if activeServerId <> invalid and activeServerId <> "" then
accessToken = ConnectionManager().GetServerData(activeServerId, "AccessToken")
if firstOf(accessToken, "") <> "" then
m.Http.AddHeader("X-MediaBrowser-Token", accessToken)
end if
end if
currentUrl = firstOf(m.GetUrl(), "")
End Function
'**********************************************************
'** Get Url
'**********************************************************
Function http_get_url() As String
return m.Http.GetUrl()
End Function
'**********************************************************
'** Set Request Method
'**********************************************************
Function http_set_request(request as String) As Void
m.Http.SetRequest(request)
End Function
'**********************************************************
'** Prepare the current url for adding query parameters
'** Automatically add a '?' or '&' as necessary
'**********************************************************
Function http_prepare_url_for_query() As String
url = m.Http.GetUrl()
if m.FirstParam Or m.CountParams = 0 then
url = url + "?"
m.FirstParam = false
else
url = url + "&"
end if
m.Http.SetUrl(url)
return url
End Function
'**********************************************************
'** Percent encode a name/value parameter pair and add the
'** the query portion of the current url
'** Automatically add a '?' or '&' as necessary
'** Prevent duplicate parameters
'**********************************************************
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)
m.CountParams = m.CountParams + 1
End Function
'**********************************************************
'** Update a query parameter
'**********************************************************
Function http_update_param(name As String, val As String) as Void
End Function
'**********************************************************
'** Remove a query parameter
'**********************************************************
Function http_remove_param(name As String) as Void
p = m.Http.Escape(name)
r = CreateObject("roRegex", "&" + p + "(\=[^&]*)?(?=&|$)", "i")
url = m.Http.GetUrl()
if r.IsMatch(url)
new_url = r.Replace(url, "")
else
r = CreateObject("roRegex", "\?" + p + "(\=[^&]*)?(?=&|$)&?", "i")
if m.CountParams = 1 ' Removing last parameter
new_url = r.Replace(url, "")
else
new_url = r.Replace(url, "?")
End if
end If
m.CountParams = m.CountParams - 1
m.Http.SetUrl(new_url)
End Function
'**********************************************************
'** Build a query string from array
'**********************************************************
Function http_build_query(query As Object) as Void
for each key in query
m.AddParam(key, query[key])
end for
End Function
'**********************************************************
'** Tack a raw query string onto the end of the current url
'** Automatically add a '?' or '&' as necessary
'**********************************************************
Function http_add_raw_query(query As String) as Void
url = m.PrepareUrlForQuery()
url = url + query
m.Http.SetUrl(url)
End Function
'**********************************************************
'** Performs Http.AsyncGetToString() in a retry loop
'** with exponential backoff. To the outside
'** world this appears as a synchronous API.
'**********************************************************
Function http_get_to_string_with_retry() As Dynamic
timeout% = 1500
num_retries% = 5
str = invalid
while num_retries% > 0
'print "httpget try " + itostr(num_retries%)
if (m.Http.AsyncGetToString())
event = wait(timeout%, m.Http.GetPort())
if type(event) = "roUrlEvent"
code = event.GetResponseCode()
if code = 200
str = event.GetString()
else
Debug("Failed Response with Error: " + itostr(code))
end if
exit while
else if event = invalid
m.Http.AsyncCancel()
' reset the connection on timeouts
m.Http = CreateURLTransferObject(m.Http.GetUrl())
timeout% = 2 * timeout%
else
Debug("AsyncGetToString Unknown Event: " + event)
end if
end if
num_retries% = num_retries% - 1
end while
return str
End Function
'**********************************************************
'** Performs Http.AsyncGetToString() with a single timeout in seconds
'** To the outside world this appears as a synchronous API.
'**********************************************************
Function http_get_to_string_with_timeout(seconds as Integer) As Dynamic
timeout% = 1000 * seconds
str = invalid
m.Http.EnableFreshConnection(true) 'Don't reuse existing connections
if (m.Http.AsyncGetToString())
event = wait(timeout%, m.Http.GetPort())
if type(event) = "roUrlEvent"
code = event.GetResponseCode()
if code = 200
str = event.GetString()
else
Debug("Failed Response with Error: " + itostr(code))
end if
else if event = invalid
Debug("AsyncGetToString timeout")
m.Http.AsyncCancel()
else
Debug("AsyncGetToString Unknown Event: " + event)
end if
end if
return str
End Function
'**********************************************************
'** Performs Http.AsyncPostFromString() with a single timeout in seconds
'** To the outside world this appears as a synchronous API.
'**********************************************************
Function http_post_from_string_with_timeout(val As String, seconds as Integer) As Dynamic
timeout% = 1000 * seconds
str = invalid
'm.Http.EnableFreshConnection(true) 'Don't reuse existing connections
if (m.Http.AsyncPostFromString(val))
event = wait(timeout%, m.Http.GetPort())
if type(event) = "roUrlEvent"
code = event.GetResponseCode()
if code = 200
str = event.GetString()
else if code = 204
str = ""
else
Debug("Failed Response with Error: (" + itostr(code) + ") " + event.GetFailureReason())
end if
else if event = invalid
Debug("AsyncPostFromString timeout")
m.Http.AsyncCancel()
else
Debug("AsyncPostFromString Unknown Event: " + event)
end if
end if
return str
End Function