Difference between revisions of "LSL HTTP server"

From Second Life Wiki
Jump to navigation Jump to search
Line 3: Line 3:


== Design ==
== Design ==
(Updated by [[User:Kelly Linden|Kelly Linden]] 11:28, 13 June 2008 (PDT))
(Updated by [[User:Kelly Linden|Kelly Linden]] 11:19, 2 September 2008 (PDT))


This design is in flux during development.  Please comment on the discussion page, as comments here tend to get lost when the design is updated.  Thanks.
This design is in flux during development.  Please comment on the discussion page, as comments here tend to get lost when the design is updated.  Thanks.
Line 10: Line 10:
   
   
=== URLs / Namespace ===
=== URLs / Namespace ===
  public url: ''https://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221''
  url: ''http://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221''
  request: ''curl https://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221{untrusted-arg}''
  request: ''curl http://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221{untrusted-arg}''
  {untrusted-arg} examples: ''/foo/bar'', ''?foo=bar'', ''/foo/bar?one=1''
  {untrusted-arg} examples: ''/foo/bar'', ''?foo=bar'', ''/foo/bar?one=1''


=== LSL ===
=== LSL ===
* '''key llRequestPublicURL()'''
* '''key llRequestURL()'''
: Request a new LSL Server public URL.  
: Request a new LSL Server public URL.  
: An http_request event will be triggered with success or failure and include the returned key
: An http_request event will be triggered with success or failure and include the returned key
  lsl: request_id = llRequestPublicURL();  
  lsl: request_id = llRequestURL();  
* '''llReleasePublicURL(string url)'''
* '''key llRequestSecureURL()'''
: Clear the specific public url
: Similar to ''llRequestURL'' except requests an HTTPS / SSL URL.
  lsl: llReleasePublicURL("https://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221");
: An http_request event will be triggered with success or failure and include the returned key
lsl: request_id = llRequestSecureURL();
* '''llReleaseURL(string url)'''
: Clear the specific URL, used for both secure and non-secure URLs.
  lsl: llReleaseURL("http://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221");
* '''http_request(key id, string method, string body)'''
* '''http_request(key id, string method, string body)'''
: Event triggered when an URL is hit:
: Event triggered when an URL is hit:
Line 27: Line 31:
:* Supported methods are GET/POST/PUT/DELETE
:* Supported methods are GET/POST/PUT/DELETE
:* body: The body of the request.
:* body: The body of the request.
: Event also triggered with response to llRequestPublicURL
: Event also triggered with response to ''llRequestURL'' and ''llRequestSecureURL''
:* id matches the key returned by llRequestPublicURL
:* id matches the key returned by ''llRequestURL'' or ''llRequestSecureURL''
:* method == URL_REQUEST_GRANTED for success, URL_REQUEST_DENIED for failure to get an URL
:* method == URL_REQUEST_GRANTED for success, URL_REQUEST_DENIED for failure to get an URL
:* body is the public URL.  If unable to get a public URL body will be empty.
:* body is the public URL.  If unable to get a public URL body will be empty.
Line 41: Line 45:
::* "x-query-string": Any query arguments, the text past a ? in the url
::* "x-query-string": Any query arguments, the text past a ? in the url
::* "x-forwarded-for": The host that made the request
::* "x-forwarded-for": The host that made the request
::* "x-forwarded-for-port": The port from the requester
::* "user-agent": The user-agent header as reported by the requester  
::* "user-agent": The user-agent header as reported by the requester  
  requested url: ''https://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221/foo/bar?arg=gra''
  requested url: ''https://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221/foo/bar?arg=gra''
Line 69: Line 72:
:* Not all requests for an url will succeed, the scripter is expected to handle the failure case.
:* Not all requests for an url will succeed, the scripter is expected to handle the failure case.
:* The number of available urls will be based on the amount of land owned in the region
:* The number of available urls will be based on the amount of land owned in the region
:* '''integer llGetFreePublicURLs()''' returns how many public URLs are available.
:* '''integer llGetFreeURLs()''' returns how many URLs are available.


=== Cap Server ===
=== Cap Server ===
* Grants caps per normal that look like:
* Grants caps that that look like:
  public url: https://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221
  http://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221
* Optionally grants SSL caps that look like:
https://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221
* Trailing path after the cap ID is passed to the internal url as part of the header:
* Trailing path after the cap ID is passed to the internal url as part of the header:
  request: https://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221/foo/bar?one=1
  request: http://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221/foo/bar?one=1
  forwarded to: <internal_url>
  forwarded to: <internal_url>
   w/ header: x-untrusted-path: foo/bar?one=1
   w/ headers: x-script-url: ''https://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221''
* Regions are aware of cap server resets (to notify scripts)
              x-path-info: ''/foo/bar''
              x-query-string: ''one=1''


== Questions / Issues ==
== Questions / Issues ==
* Should these caps time out?
* Define response codes - no script/object found, throttled.
* Define response codes - no script/object found, throttled.
* Define mime-handling
* Define mime-handling
  I believe that we should, like the llHTTPRequest() call, be very clear in our handling of bodies and mime-types.
*: We will transcode incoming data to UTF-8. Per standards if no type is defined we assume the web standard of 'iso-8859-1'.
In particular, accept only text/* mime types, and be sure to do proper charset handling and conversion into the
*: Content type of responses will be 'text/plain; charset=utf-8'
UTF-8 that LSL strings use.  (The code should all be cullable from the llHTTPRequest() implementation.)
[[User:Zero Linden|Zero Linden]] 14:37, 16 November 2007 (PST)


== Interface Requirements ==
== Interface Requirements ==
Line 116: Line 119:


== Limitations ==
== Limitations ==
* Size of the body of the requests will probably need to be limited.  At least to something that will fit within script memory.
* Size of the body of the requests will be limited to 2k bytes.
This is needed to keep from overloading scripts and to reduce the overall potential load of handling large sets of data.
* Size of headers of requests will be limited to 255 bytes.
We also need to limit the size of returned data in llHTTPResponse()
* The size of responses to requests is not currently limited, but this is subject to review during testing.
[[User:Kelly Linden|Kelly Linden]] 12:58, 14 May 2008 (PDT)
* There is a cap of 64 in flight requests per script.
* There will be a max number of 'in process' requests allowed per script (requests that have been made but not responded to or timed out yet), requests when past this limit will receive an appropriate http status code.  This will be roughly on the order of maximum number of queued events in a script, give or take a factor of 2.
* We may throttle at the CAP server level as well.  This is possible, but has not yet been decided.
* We may wish to throttle at the CAP server level as well, if possible.


== Interactions ==
== Interactions ==
Line 129: Line 131:


== Testing ==
== Testing ==
* Some example scripts: [[LSL http server/examples]]
TODO: Export internal test plan pages.
TODO: Export internal test plan pages.



Revision as of 11:19, 2 September 2008

Goals

Create an alternative to the XMLRPC server and email gateway for communication with LSL scripts initiated from outside Second Life that is easy to use and scalable. Extra bonus for enabling LSL -> LSL communication at the same time.

Design

(Updated by Kelly Linden 11:19, 2 September 2008 (PDT))

This design is in flux during development. Please comment on the discussion page, as comments here tend to get lost when the design is updated. Thanks.

A teaser image.

URLs / Namespace

url: http://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221
request: curl http://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221{untrusted-arg}
{untrusted-arg} examples: /foo/bar, ?foo=bar, /foo/bar?one=1

LSL

  • key llRequestURL()
Request a new LSL Server public URL.
An http_request event will be triggered with success or failure and include the returned key
lsl: request_id = llRequestURL(); 
  • key llRequestSecureURL()
Similar to llRequestURL except requests an HTTPS / SSL URL.
An http_request event will be triggered with success or failure and include the returned key
lsl: request_id = llRequestSecureURL(); 
  • llReleaseURL(string url)
Clear the specific URL, used for both secure and non-secure URLs.
lsl: llReleaseURL("http://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221");
  • http_request(key id, string method, string body)
Event triggered when an URL is hit:
  • id is unique to this request
  • Supported methods are GET/POST/PUT/DELETE
  • body: The body of the request.
Event also triggered with response to llRequestURL and llRequestSecureURL
  • id matches the key returned by llRequestURL or llRequestSecureURL
  • method == URL_REQUEST_GRANTED for success, URL_REQUEST_DENIED for failure to get an URL
  • body is the public URL. If unable to get a public URL body will be empty.
  • llHTTPResponse(key id, integer status, string body)
Send body to the requester with status code status
  • id is the id from http_request that maps to the specific request
  • string llHTTPHeader(key id, string header)
Returns the string for the specified header in the specified request
  • Supported headers are:
  • "x-script-url": The base url, as originally recieved from llRequestPublicURL
  • "x-path-info": Any trailing path information from the requested url
  • "x-query-string": Any query arguments, the text past a ? in the url
  • "x-forwarded-for": The host that made the request
  • "user-agent": The user-agent header as reported by the requester
requested url: https://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221/foo/bar?arg=gra
x-script-url: https://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221
x-path-info: /foo/bar
x-query-string: arg=gra
  • changed(integer change)
  • CHANGED_REGION_RESTART: New changed() event triggered on region startup.

Simulator

What the simulator needs to do:

  • Pass the headers mentioned above into the lsl script:
  • Clear/invalidate caps in some situations:
  • Caps will automatically be revoked when the region goes down.
  • When the script is reset, resaved or deleted.
  • Object removed from world
  • Object region change
  • Object owner change
  • Region startup (clear all by region)
  • Script request (llReleasePublicURL)
  • Scripts should know when they need to re-request urls
Goal: Scripts should be able to know when public urls are lost and recover from that loss
  • Existing events: default/state_entry (new script), on_rez, changed(region cross, owner)
  • New events: cap server is restarted, region is restarted
  • This is a first use for a more general Limited Script Resource system that should eventually also handle script memory and cpu cycles.
  • Not all requests for an url will succeed, the scripter is expected to handle the failure case.
  • The number of available urls will be based on the amount of land owned in the region
  • integer llGetFreeURLs() returns how many URLs are available.

Cap Server

  • Grants caps that that look like:
http://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221
  • Optionally grants SSL caps that look like:
https://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221
  • Trailing path after the cap ID is passed to the internal url as part of the header:
request: http://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221/foo/bar?one=1
forwarded to: <internal_url>
  w/ headers: x-script-url: https://sim123.agni/cap/f23b4b94-012d-44f2-bd0c-16c328321221
              x-path-info: /foo/bar
              x-query-string: one=1

Questions / Issues

  • Define response codes - no script/object found, throttled.
  • Define mime-handling
    We will transcode incoming data to UTF-8. Per standards if no type is defined we assume the web standard of 'iso-8859-1'.
    Content type of responses will be 'text/plain; charset=utf-8'

Interface Requirements

  • No GUI components.
  • LSL Functions are written in stone, must get them right.

Performance Requirements

This should add no database, assetserver or viewer load.

Simulator:

  • In general load should be no higher than existing alternatives (xmlrpc, llemail and llhttprequest) for any single action.
  • Connections need to be throttled.
It would be nice if this could happen before the simulator on a per-cap basis, but throttling in the simulator handler would probably work as well.

Capserver:

  • TBD: More info on cap server's load characteristics. We believe this will be ok, especially in the world of unified cap server, multi-threaded apache and memcached - but we need to verify.
  • Separate apache config and/or resource pools for agent caps vs task/LSL caps would give us opportunities to ensure good behavior for agent critical features at the expense of LSL/Caps performance if needed and allow us to minimize the impact of DOS style attacks against the LSL caps.

TODO:

  • Get statistics on # of XMLRPC connections, llHTTPRequests and llEmails per unit of time per region to set expectations for level of usage.
We currently have 2 XMLRPC servers each processing about 30-40 concurrent requests.
I don't know the actual rate of requests, but I do know that we start failing at ~150
concurrent requests (out of a theoretical max of 200) per server, or ~300 total.
Kelly Linden 12:52, 14 May 2008 (PDT)

Security Impact

Creating a server accessible in any way from outside needs to be done with care. The cap server already does this, and security concerns should already be handled here. This isn't something to take for granted though.

  • Scripts should not be blocked from using llHTTPRequest to contact the public interface of the cap server.
  • Need to be careful about this since these are requests that originate from inside our network.

Limitations

  • Size of the body of the requests will be limited to 2k bytes.
  • Size of headers of requests will be limited to 255 bytes.
  • The size of responses to requests is not currently limited, but this is subject to review during testing.
  • There is a cap of 64 in flight requests per script.
  • We may throttle at the CAP server level as well. This is possible, but has not yet been decided.

Interactions

Testing

TODO: Export internal test plan pages.

Previous Design

Previous design and comments