Difference between revisions of "LlRequestURL"

From Second Life Wiki
Jump to navigation Jump to search
m
(Replaced <source> with <syntaxhighlight>, added some wikilinks, cleaned up code to conform to best practices)
 
(24 intermediate revisions by 9 users not shown)
Line 1: Line 1:
{{LSL_Function
{{LSL_Function
|inject-2={{Issues/BUG-3813}}
|func_id=345|func_sleep=0.0|func_energy=10.0|mode
|func_id=345|func_sleep=0.0|func_energy=10.0|mode
|func=llRequestURL|return_type=key
|func=llRequestURL
|return_type=key|return_subtype=handle
|func_footnote=
|func_footnote=
|func_desc=Requests one HTTP:// url for use by this script. The [[http_request]] event is triggered with the result of the request.
|func_desc=Requests one <code>HTTP://</code> {{Wikipedia|URL}} for use by this [[script]]. The [[http_request]] [[event]] is triggered with the result of the request.
|return_text=that is the handle used for identifying the result in the [[http_request]] event.
|return_text=used for identifying the result of the request in the [[http_request]] [[event]].
|spec
|spec
|caveats=*When a region is (re)started all [[http_request|HTTP server]] URLs are automatically released and invalidated.
|caveats=
*HTTP-in is not on the usual [[HTTP]] port number; the URL it provided in the [[http_request]] event includes the correct port number.
*Your script (and any client that uses it) should not "validate" the provided URL; in particular, do not assume that it maps to any particular address, or is in any particular domain. These will change during the uplift of Second Life to the cloud, and may be more dynamic following that uplift<ref>Occurred ''ca.'' 2020.</ref>.
*Use of this function is [[Limits|throttled]]. Although it has no forced sleep time, too many requests (5-ish) in a short period will cause all further requests to be denied until the script stops requesting URLs for at least 1 second. Using an [[llSleep]] of 0.6 seconds or greater between each request will prevent you from being throttled.
*When a region is (re)started all [[http_request|HTTP server]] URLs are automatically released and invalidated.
**Use [[CHANGED_REGION_START]] to detect this so new URL can be requested.
**Use [[CHANGED_REGION_START]] to detect this so new URL can be requested.
*The number of available URLs is a limited resource, that is to say, a script can only have so many open URLs. See [[LSL http_server#Resource Limitations]] for details.
*The number of available URLs is a limited resource, that is to say, a script can only have so many open URLs. See [[LSL http_server#Resource Limitations]] for details.
*When abandoning a URL, always release it with [[llReleaseURL]], otherwise it will leak.
*When abandoning a URL, release it with [[llReleaseURL]], to avoid leaks. Resetting the script, or deleting the prim, will also suffice to release URLs.
*Unlike [[llListen|listeners]], URLs persist across state changes
 
|constants
|constants
|examples=
|examples=
This script requests a new URL after region restart:
A fully worked out example that shows how to get a URL, register that URL with an external client, and do proper backoff and retry for contacting external services can be found at [[HTTP Server URL Registration]].
<LSL>string url;
 
This script requests a new URL after region restart.
 
See the discussion page for explanations as to why this particular script never needs to use [[llReleaseURL]]().
<syntaxhighlight lang="lsl2">
string url;
key urlRequestId;


default {
default
    state_entry() {
{
        //Requesting a URL
state_entry()
        llRequestURL();
{
    }
urlRequestId = llRequestURL();
    changed(integer What) {
}
        //Region restarted
        if (What & CHANGED_REGION_START) {
on_rez(integer start_param)
            //Request new URL
{
            llRequestURL();
llResetScript();
        }
}
    }
 
    http_request(key ID, string Method, string Body) {
changed(integer change)
        if (Method == URL_REQUEST_GRANTED) {
{
            //Saying URL to owner
if (change & (CHANGED_OWNER | CHANGED_INVENTORY))
            url = Body;
{
            llOwnerSay(url);
llResetScript();
        } else if (Method == URL_REQUEST_DENIED) {
}
            llOwnerSay("No URLs free !");
if (change & (CHANGED_REGION | CHANGED_REGION_START | CHANGED_TELEPORT))
        } else if (Method == "GET") {
{
            llHTTPResponse(ID, 200, "Hello there !");
urlRequestId = llRequestURL();
        }
}
    }
}
}</LSL>
 
http_request(key id, string method, string body)
{
if (id == urlRequestId)
{
if (method == URL_REQUEST_DENIED)
{
llOwnerSay("The following error occurred while attempting to get a free URL for this device:\n\n" + body);
}
else if (method == URL_REQUEST_GRANTED)
{
url = body;
llLoadURL(llGetOwner(), "Click to visit my URL!", url);
}
}
}
}
</syntaxhighlight>
It's important to keep in mind that if you request another URL, that the old one will not be released, it will remain active. The following script drives home this point.
It's important to keep in mind that if you request another URL, that the old one will not be released, it will remain active. The following script drives home this point.


Try the following code ONLY if you can use all your URLs on your land.
Try the following code ONLY if you can use all your URLs on your land.
Removing the prim/script will release all URLs previous assigned.
Removing the prim/script will release all URLs previous assigned.
<LSL>//Quickly allocates all available URLs
<syntaxhighlight lang="lsl2">
//Touching
// WARNING:
 
//
//deleting the script or derezzing the prim/object to releases the URLs
//      This script is only for proof-of-concept (demo purposes).
 
//      DO NOT use it if you don't have the sim owners and/or
//      estate managers OK to test this script.
//      This script can possibly block HTTP communication from and to the sim.
//      ...bringing down all networked vendors and/or similar machines.
//
//      This script allocates all available URLs.
//     Deleting the script and/or derezzing the object containing the script,
//      will release all previously taken URLs.


default
{
state_entry()
{
llRequestURL();
}


default {
http_request(key id, string method, string body)
    state_entry() {
{
        //Requesting a URL
if (method == URL_REQUEST_DENIED)
        llRequestURL();
{
    }
llSetText("No free URLs!", <1.0, 0.0, 0.0>, 1.0);
    http_request(key ID, string Method, string Body) {
}
        if (Method == URL_REQUEST_GRANTED) {
else if (method == URL_REQUEST_GRANTED)
            //Printing new URL and number of free addresses
{
            llSetText( (string)llGetFreeURLs() + "\n" + Body, <1, 1, 1 >, 1);
llSetText((string)llGetFreeURLs() + " URLs left\n" + body, <1.0, 1.0, 1.0>, 1.0);
            //Requesting a URL
llRequestURL();
            llRequestURL();
}
        } else if (Method == URL_REQUEST_DENIED) {
else if (method == "GET")
            llSetText("No URLs free !", <1, 0, 0 >, 1);
{
        } else if (Method == "GET") {
llHTTPResponse(id, 200, "Hello there!");
            llHTTPResponse(ID, 200, "Hello there !");
}
        }
}
    }
}
}</LSL>
</syntaxhighlight>
This script will, as you can see, use all URLs available on your land because it does not remove the old URLs before requesting a new one.
This script will, as you can see, use all URLs available on your land because it does not remove the old URLs before requesting a new one.
Just store the old URL in a global variable and release it with [[llReleaseURL]].
Just store the old URL in a global variable and release it with [[llReleaseURL]].
Line 81: Line 125:
|also_articles=
|also_articles=
{{LSL DefineRow||[[LSL http server]]}}
{{LSL DefineRow||[[LSL http server]]}}
|notes
|notes=
{{Quote|Another comment on resilient programming: getting a global resource, an HTTP listener in this case, should always be considered an operation that can fail for transitory reasons (as well as permanent ones). In this case, LSL folds retryable and permanent errors into the same error status and there's no opportunity for a script writer to distinguish the two cases. But a reasonable way to handle this is sleeping with limited retries before failing hard in the LSL code.|2=[https://jira.secondlife.com/browse/BUG-3813?focusedCommentId=399955&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-399955 Monty Linden]}}
|deepnotes=
|deepnotes=
|history=
|history=
*{{SVN|1836|rev=112899 |trunk=*|anchor=file22|ver=|ser=}}
*{{SVN|1836|rev=112899 |trunk=*|anchor=file22|ver=|ser=}}
|comments
|cat1=HTTP
|cat1=HTTP
|cat2=HTTP/Server
|cat2=HTTP/Server

Latest revision as of 03:49, 11 June 2023

Summary

Function: key llRequestURL( );
0.0 Forced Delay
10.0 Energy

Requests one HTTP:// "Wikipedia logo"URL for use by this script. The http_request event is triggered with the result of the request.
Returns a handle (a key) used for identifying the result of the request in the http_request event.

Caveats

  • HTTP-in is not on the usual HTTP port number; the URL it provided in the http_request event includes the correct port number.
  • Your script (and any client that uses it) should not "validate" the provided URL; in particular, do not assume that it maps to any particular address, or is in any particular domain. These will change during the uplift of Second Life to the cloud, and may be more dynamic following that uplift[1].
  • Use of this function is throttled. Although it has no forced sleep time, too many requests (5-ish) in a short period will cause all further requests to be denied until the script stops requesting URLs for at least 1 second. Using an llSleep of 0.6 seconds or greater between each request will prevent you from being throttled.
  • When a region is (re)started all HTTP server URLs are automatically released and invalidated.
  • The number of available URLs is a limited resource, that is to say, a script can only have so many open URLs. See LSL http_server#Resource Limitations for details.
  • When abandoning a URL, release it with llReleaseURL, to avoid leaks. Resetting the script, or deleting the prim, will also suffice to release URLs.
  • Unlike listeners, URLs persist across state changes

Examples

A fully worked out example that shows how to get a URL, register that URL with an external client, and do proper backoff and retry for contacting external services can be found at HTTP Server URL Registration.

This script requests a new URL after region restart.

See the discussion page for explanations as to why this particular script never needs to use llReleaseURL().

string url;
key urlRequestId;

default
{
	state_entry()
	{
		urlRequestId = llRequestURL();
	}
	
	on_rez(integer start_param)
	{
		llResetScript();
	}

	changed(integer change)
	{
		if (change & (CHANGED_OWNER | CHANGED_INVENTORY))
		{
			llResetScript();
		}
		if (change & (CHANGED_REGION | CHANGED_REGION_START | CHANGED_TELEPORT))
		{
			urlRequestId = llRequestURL();
		}
	}

	http_request(key id, string method, string body)
	{
		if (id == urlRequestId)
		{
			if (method == URL_REQUEST_DENIED)
			{
				llOwnerSay("The following error occurred while attempting to get a free URL for this device:\n\n" + body);
			}
			else if (method == URL_REQUEST_GRANTED)
			{
				url = body;
				llLoadURL(llGetOwner(), "Click to visit my URL!", url);
			}
		}
	}
}

It's important to keep in mind that if you request another URL, that the old one will not be released, it will remain active. The following script drives home this point.

Try the following code ONLY if you can use all your URLs on your land. Removing the prim/script will release all URLs previous assigned.

// WARNING:
//
//      This script is only for proof-of-concept (demo purposes).
//      DO NOT use it if you don't have the sim owners and/or
//      estate managers OK to test this script.
//      This script can possibly block HTTP communication from and to the sim.
//      ...bringing down all networked vendors and/or similar machines.
//
//      This script allocates all available URLs.
//      Deleting the script and/or derezzing the object containing the script,
//      will release all previously taken URLs.

default
{
	state_entry()
	{
		llRequestURL();
	}

	http_request(key id, string method, string body)
	{
		if (method == URL_REQUEST_DENIED)
		{
			llSetText("No free URLs!", <1.0, 0.0, 0.0>, 1.0);
		}
		else if (method == URL_REQUEST_GRANTED)
		{
			llSetText((string)llGetFreeURLs() + " URLs left\n" + body, <1.0, 1.0, 1.0>, 1.0);
			llRequestURL();
		}
		else if (method == "GET")
		{
			llHTTPResponse(id, 200, "Hello there!");
		}
	}
}

This script will, as you can see, use all URLs available on your land because it does not remove the old URLs before requesting a new one.

Just store the old URL in a global variable and release it with llReleaseURL.

Notes

Another comment on resilient programming: getting a global resource, an HTTP listener in this case, should always be considered an operation that can fail for transitory reasons (as well as permanent ones). In this case, LSL folds retryable and permanent errors into the same error status and there's no opportunity for a script writer to distinguish the two cases. But a reasonable way to handle this is sleeping with limited retries before failing hard in the LSL code.
Monty Linden

See Also

Functions

•  llRequestSecureURL
•  llGetFreeURLs
•  llReleaseURL
•  llHTTPResponse
•  llGetHTTPHeader

Articles

•  LSL http server

Deep Notes

History

Signature

function key llRequestURL();
  1. Occurred ca. 2020.