public LSL_String llHTTPRequest(string url, LSL_List parameters, string body)
{
// Partial implementation: support for parameter flags needed
// see http://wiki.secondlife.com/wiki/LlHTTPRequest
// parameter flags support are implemented in ScriptsHttpRequests.cs
// in StartHttpRequest
m_host.AddScriptLPS(1);
IHttpRequestModule httpScriptMod =
m_ScriptEngine.World.RequestModuleInterface<IHttpRequestModule>();
List<string> param = new List<string>();
bool ok;
Int32 flag;
for (int i = 0; i < parameters.Data.Length; i += 2)
{
ok = Int32.TryParse(parameters.Data[i].ToString(), out flag);
if (!ok || flag < 0 ||
flag > (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE)
{
Error("llHTTPRequest", "Parameter " + i.ToString() + " is an invalid flag");
}
param.Add(parameters.Data[i].ToString()); //Add parameter flag
if (flag != (int)HttpRequestConstants.HTTP_CUSTOM_HEADER)
{
param.Add(parameters.Data[i+1].ToString()); //Add parameter value
}
else
{
//Parameters are in pairs and custom header takes
//arguments in pairs so adjust for header marker.
++i;
//Maximum of 8 headers are allowed based on the
//Second Life documentation for llHTTPRequest.
for (int count = 1; count <= 8; ++count)
{
//Enough parameters remaining for (another) header?
if (parameters.Data.Length - i < 2)
{
//There must be at least one name/value pair for custom header
if (count == 1)
Error("llHTTPRequest", "Missing name/value for custom header at parameter " + i.ToString());
break;
}
if (HttpStandardHeaders.Contains(parameters.Data[i].ToString(), StringComparer.OrdinalIgnoreCase))
Error("llHTTPRequest", "Name is invalid as a custom header at parameter " + i.ToString());
param.Add(parameters.Data[i].ToString());
param.Add(parameters.Data[i+1].ToString());
//Have we reached the end of the list of headers?
//End is marked by a string with a single digit.
if (i+2 >= parameters.Data.Length ||
Char.IsDigit(parameters.Data[i].ToString()[0]))
{
break;
}
i += 2;
}
}
}
Vector3 position = m_host.AbsolutePosition;
Vector3 velocity = m_host.Velocity;
Quaternion rotation = m_host.RotationOffset;
string ownerName = String.Empty;
ScenePresence scenePresence = World.GetScenePresence(m_host.OwnerID);
if (scenePresence == null)
ownerName = resolveName(m_host.OwnerID);
else
ownerName = scenePresence.Name;
RegionInfo regionInfo = World.RegionInfo;
Dictionary<string, string> httpHeaders = new Dictionary<string, string>();
string shard = "OpenSim";
IConfigSource config = m_ScriptEngine.ConfigSource;
if (config.Configs["Network"] != null)
{
shard = config.Configs["Network"].GetString("shard", shard);
}
httpHeaders["X-SecondLife-Shard"] = shard;
httpHeaders["X-SecondLife-Object-Name"] = m_host.Name;
httpHeaders["X-SecondLife-Object-Key"] = m_host.UUID.ToString();
httpHeaders["X-SecondLife-Region"] = string.Format("{0} ({1}, {2})", regionInfo.RegionName, regionInfo.RegionLocX, regionInfo.RegionLocY);
httpHeaders["X-SecondLife-Local-Position"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", position.X, position.Y, position.Z);
httpHeaders["X-SecondLife-Local-Velocity"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", velocity.X, velocity.Y, velocity.Z);
httpHeaders["X-SecondLife-Local-Rotation"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000}, {3:0.000000})", rotation.X, rotation.Y, rotation.Z, rotation.W);
httpHeaders["X-SecondLife-Owner-Name"] = ownerName;
httpHeaders["X-SecondLife-Owner-Key"] = m_host.OwnerID.ToString();
string userAgent = config.Configs["Network"].GetString("user_agent", null);
if (userAgent != null)
httpHeaders["User-Agent"] = userAgent;
// See if the URL contains any header hacks
string[] urlParts = url.Split(new char[] {'\n'});
if (urlParts.Length > 1)
{
// Iterate the passed headers and parse them
for (int i = 1 ; i < urlParts.Length ; i++ )
{
// The rest of those would be added to the body in SL.
// Let's not do that.
if (urlParts[i] == String.Empty)
break;
// See if this could be a valid header
string[] headerParts = urlParts[i].Split(new char[] {':'}, 2);
if (headerParts.Length != 2)
continue;
string headerName = headerParts[0].Trim();
string headerValue = headerParts[1].Trim();
// Filter out headers that could be used to abuse
// another system or cloak the request
if (headerName.ToLower() == "x-secondlife-shard" ||
headerName.ToLower() == "x-secondlife-object-name" ||
headerName.ToLower() == "x-secondlife-object-key" ||
headerName.ToLower() == "x-secondlife-region" ||
headerName.ToLower() == "x-secondlife-local-position" ||
headerName.ToLower() == "x-secondlife-local-velocity" ||
headerName.ToLower() == "x-secondlife-local-rotation" ||
headerName.ToLower() == "x-secondlife-owner-name" ||
headerName.ToLower() == "x-secondlife-owner-key" ||
headerName.ToLower() == "connection" ||
headerName.ToLower() == "content-length" ||
headerName.ToLower() == "from" ||
headerName.ToLower() == "host" ||
headerName.ToLower() == "proxy-authorization" ||
headerName.ToLower() == "referer" ||
headerName.ToLower() == "trailer" ||
headerName.ToLower() == "transfer-encoding" ||
headerName.ToLower() == "via" ||
headerName.ToLower() == "authorization")
continue;
httpHeaders[headerName] = headerValue;
}
// Finally, strip any protocol specifier from the URL
url = urlParts[0].Trim();
int idx = url.IndexOf(" HTTP/");
if (idx != -1)
url = url.Substring(0, idx);
}
string authregex = @"^(https?:\/\/)(\w+):(\w+)@(.*)$";
Regex r = new Regex(authregex);
int[] gnums = r.GetGroupNumbers();
Match m = r.Match(url);
if (m.Success)
{
for (int i = 1; i < gnums.Length; i++)
{
//System.Text.RegularExpressions.Group g = m.Groups[gnums[i]];
//CaptureCollection cc = g.Captures;
}
if (m.Groups.Count == 5)
{
httpHeaders["Authorization"] = String.Format("Basic {0}", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(m.Groups[2].ToString() + ":" + m.Groups[3].ToString())));
url = m.Groups[1].ToString() + m.Groups[4].ToString();
}
}
HttpInitialRequestStatus status;
UUID reqID
= httpScriptMod.StartHttpRequest(m_host.LocalId, m_item.ItemID, url, param, httpHeaders, body, out status);
if (status == HttpInitialRequestStatus.DISALLOWED_BY_FILTER)
Error("llHttpRequest", string.Format("Request to {0} disallowed by filter", url));
if (reqID != UUID.Zero)
return reqID.ToString();
else
return null;
}