URLConnection Session Question

I have encountered a situation where I am trying to remotely control a device (a video camera) over HTTP and I am getting a session error. Basically I’m trying to mimic in my code what the web browser would do. I’ve gone into the device’s web page and examined the JavaScript and found the URI for the command I want to execute. If I just send that directly, I get a session error. This happens if I send the command in a browser by itself or if I send it from Xojo using a URLConnection.

However, if I have the camera’s web app open in a browser and then send the desired command from another tab in the browser, it works. So then in Xojo I load the webpage using a URLConnection and a GET command. Then I wait a few seconds and using the same URLConnection, I send the command I am trying to send the device. I am still getting a session error. I am using the same URLConnection. It hasn’t closed and I haven’t re-initialized it.

Does a URLConnection create a new session each time a GET command is sent? How can I get around this?

Thanks!

Perhaps the webpage is setting a cookie? Load the webpage with a URLConnection and check the response headers for one or more Set-Cookie headers.

2 Likes

If it did set a cookie, is there any way around this? I have to go back to the site and turn the camera back on so I don’t have an immediate answer…

OK. Here is what I get back from the camera when I connect to it’s default page:

> <!DOCTYPE html>
> <html>
> <!-- Copyright CANON INC. -->
> 	<head>
> 		<meta name="copyright" content="Copyright CANON INC. 2018">
> 		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
> 		<meta http-equiv="pragma" content="no-cache">
> 		<meta http-equiv="cache-control" content="no-cache">
> 		<meta http-equiv="X-UA-Compatible" content="IE=9">
> 		<meta name="apple-mobile-web-app-capable" content="yes">
> 		<meta name="format-detection" content="telephone=no"/>
> 		<script type="text/javascript" src="js/cmn/common.js"></script>
> 		<script type="text/javascript" src="js/cmn/trans.js"></script>
> 		<title>Browser Remote</title>
> 	</head>
> 	<body>
> 		<div id="ID_Control">Please wait…</div>
> 	</body>
> </html>

I don’t see any set-cookie in there…

Looking at the console in Safari when open on the page, it looks like some cookies do get set…

That’s the page contents not the headers. See URLConnection.ResponseHeaders

Your screenshot shows three cookies: acid=41b7, brlang=0, and productID=VNAX01. You’ll need to parse the Set-Cookie headers (which can include additional info like expiration dates, domain name, etc.) and send back the name=value part as a Cookie header to your next request.

So you’ll see three response headers that look something like this:

Set-Cookie: acid=41b7; domain=172.16.100.70
Set-Cookie: brlang=0; domain=172.16.100.70
Set-Cookie: productID=VNAX01; domain=172.16.100.70

Which you would send back as a single request header in the next request:

myURLConnection.RequestHeader("Cookie") = "acid=41b7; brlang=0; productID=VNAX01"

Thanks. I’ll try that. I knew that the page contents might not be what I wanted but I didn’t see any other properties of the URLConnection in the debugger. I see ResponseHeaders is an iterator so that’s why… I’ll get those headers and post them.

Ugh. Whenever I try to follow Xojo’s code:

Var headers() As String
For Each header As String In u.ResponseHeaders
  headers.AddRow(header)
Next

Where u is my URLConnection, I get a TypeMismatch exception. Something about converting a Variant to String. Which doesn’t make sense…

I’m running 2019R3.2 right now…

Try

Var headers() as string = u.ResponseHeaders

Nope. Get a compile error.

AVDevice.HTTPSockHeadersReceived, line 1
Type mismatch error.  Expected String(), but got interface Iterable
Var headers() As String = u.ResponseHeaders

Here’s the exception:

RuntimeRaiseException

_Z19RaiseExceptionClassRK13ClassDeclBase

VariantToString

AVDevice.HTTPSockHeadersReceived%

It’s in the framework. I tried making Headers() a variant and it still crashes. Maybe it’s fixed in 2020. I’ll have to try that.

Thanks to Norman Palardy for sending me an email (he’s somehow inexplicably banned from the forums) regarding this.

ResponseHeaders are Pairs not strings.

Var headers() As Pair
For Each header As Pair In u.ResponseHeaders
  headers.Append(header)
Next
1 Like

So now getting back to @Andrew_Lambert regarding the question of a cookie header. No, there isn’t one.

The headers are:

  • Date
  • Content-Type
  • Content-Length
  • Content-Language

So not sure if sending back a response with the Cookie request header will do anything. I can try though.

Perhaps the cookies are being set by a script on the page?

Not sure. I’d have to dig through all the script code. I’ll have to try setting the response header as you suggested. I’ve not done that yet.

THIS WORKED!

Thank you.

Now to just figure out how to adapt my code so this doesn’t have to be hardcoded.

Well, I have figured it out! I now have implemented an API for entering multiple HTML commands and the request header.

The motivation behind this is generic device control from a panel with a series of buttons. The button can have a number of different kinds of commands. Most are handed via TCP/IP connections, but sometimes devices require HTML control. Some devices have an actual HTML API, others like these cameras need to be reverse engineered. So I needed to do something where the user could set their own RequestHeader for whatever is needed. Here’s what the full command looks like that the user would enter for the button in this case:

http://172.16.100.70 RequestHeader(Cookie:acid=41b7; brlang=0; productID=VNAX01) DELAY10 http://172.16.100.70/api/cam/rec?cmd=trig

So I have a RegEx that extracts the RequestHeader and creates a pair. It that saves that to the object containing the URL connection. I then remove the RequestHeader section from the string. Now I have two HTML commands separated by DELAY10. DELAY10 is used to insert a 10 millisecond delay. I send all the commands from a thread so I sleep the thread between commands.

When the object that has the URLConnection receives headers back from the device, it sets the request header based on the stored pair.

I just wish manufacturers would give real APIs for controlling devices instead of making us wade through ridiculous HTML hoops. On a professional camera like this from Canon, they should know better and provide users a TCP/IP API or at least a normal HTML API.