diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index a676971a28..c2e37c44dd 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs @@ -187,6 +187,45 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest case (int)HttpRequestConstants.HTTP_VERIFY_CERT: htc.HttpVerifyCert = (int.Parse(parms[i + 1]) != 0); break; + + case (int)HttpRequestConstants.HTTP_VERBOSE_THROTTLE: + + // TODO implement me + break; + + case (int)HttpRequestConstants.HTTP_CUSTOM_HEADER: + //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) + { + //Not enough parameters remaining for a header? + if (parms.Length - i < 2) + break; + + //Have we reached the end of the list of headers? + //End is marked by a string with a single digit. + //We already know we have at least one parameter + //so it is safe to do this check at top of loop. + if (Char.IsDigit(parms[i][0])) + break; + + if (htc.HttpCustomHeaders == null) + htc.HttpCustomHeaders = new List(); + + htc.HttpCustomHeaders.Add(parms[i]); + htc.HttpCustomHeaders.Add(parms[i+1]); + + i += 2; + } + break; + + case (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE: + htc.HttpPragmaNoCache = (int.Parse(parms[i + 1]) != 0); + break; } } } @@ -328,9 +367,12 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest // public const int HTTP_METHOD = 0; // public const int HTTP_MIMETYPE = 1; // public const int HTTP_VERIFY_CERT = 3; + // public const int HTTP_VERBOSE_THROTTLE = 4; + // public const int HTTP_CUSTOM_HEADER = 5; + // public const int HTTP_PRAGMA_NO_CACHE = 6; private bool _finished; public bool Finished - { + { get { return _finished; } } // public int HttpBodyMaxLen = 2048; // not implemented @@ -340,11 +382,14 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public string HttpMIMEType = "text/plain;charset=utf-8"; public int HttpTimeout; public bool HttpVerifyCert = true; + //public bool HttpVerboseThrottle = true; // not implemented + public List HttpCustomHeaders = null; + public bool HttpPragmaNoCache = true; private Thread httpThread; // Request info private UUID _itemID; - public UUID ItemID + public UUID ItemID { get { return _itemID; } set { _itemID = value; } @@ -360,7 +405,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public string proxyexcepts; public string OutboundBody; private UUID _reqID; - public UUID ReqID + public UUID ReqID { get { return _reqID; } set { _reqID = value; } @@ -401,7 +446,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest Request.Method = HttpMethod; Request.ContentType = HttpMIMEType; - if(!HttpVerifyCert) + if (!HttpVerifyCert) { // We could hijack Connection Group Name to identify // a desired security exception. But at the moment we'll use a dummy header instead. @@ -412,14 +457,24 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest // { // Request.ConnectionGroupName="Verify"; // } - if (proxyurl != null && proxyurl.Length > 0) + if (!HttpPragmaNoCache) { - if (proxyexcepts != null && proxyexcepts.Length > 0) + Request.Headers.Add("Pragma", "no-cache"); + } + if (HttpCustomHeaders != null) + { + for (int i = 0; i < HttpCustomHeaders.Count; i += 2) + Request.Headers.Add(HttpCustomHeaders[i], + HttpCustomHeaders[i+1]); + } + if (proxyurl != null && proxyurl.Length > 0) + { + if (proxyexcepts != null && proxyexcepts.Length > 0) { string[] elist = proxyexcepts.Split(';'); Request.Proxy = new WebProxy(proxyurl, true, elist); - } - else + } + else { Request.Proxy = new WebProxy(proxyurl, true); } @@ -432,7 +487,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest Request.Headers[entry.Key] = entry.Value; // Encode outbound data - if (OutboundBody.Length > 0) + if (OutboundBody.Length > 0) { byte[] data = Util.UTF8.GetBytes(OutboundBody); diff --git a/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs b/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs index de0f2a32aa..eb6c5ac56c 100644 --- a/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs +++ b/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs @@ -36,6 +36,9 @@ namespace OpenSim.Region.Framework.Interfaces HTTP_MIMETYPE = 1, HTTP_BODY_MAXLENGTH = 2, HTTP_VERIFY_CERT = 3, + HTTP_VERBOSE_THROTTLE = 4, + HTTP_CUSTOM_HEADER = 5, + HTTP_PRAGMA_NO_CACHE = 6 } public interface IHttpRequestModule diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 1ab107aa47..42413a3c94 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -66,6 +66,7 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; using System.Reflection; +using System.Linq; namespace OpenSim.Region.ScriptEngine.Shared.Api { @@ -110,6 +111,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected int EMAIL_PAUSE_TIME = 20; // documented delay value for smtp. protected ISoundModule m_SoundModule = null; + //An array of HTTP/1.1 headers that are not allowed to be used + //as custom headers by llHTTPRequest. + private string[] HttpStandardHeaders = + { + "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language", + "Accept-Ranges", "Age", "Allow", "Authorization", "Cache-Control", + "Connection", "Content-Encoding", "Content-Language", + "Content-Length", "Content-Location", "Content-MD5", + "Content-Range", "Content-Type", "Date", "ETag", "Expect", + "Expires", "From", "Host", "If-Match", "If-Modified-Since", + "If-None-Match", "If-Range", "If-Unmodified-Since", "Last-Modified", + "Location", "Max-Forwards", "Pragma", "Proxy-Authenticate", + "Proxy-Authorization", "Range", "Referer", "Retry-After", "Server", + "TE", "Trailer", "Transfer-Encoding", "Upgrade", "User-Agent", + "Vary", "Via", "Warning", "WWW-Authenticate" + }; + public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) { m_ScriptEngine = ScriptEngine; @@ -1522,7 +1540,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (tex.FaceTextures[i] != null) { tex.FaceTextures[i].Shiny = sval; - tex.FaceTextures[i].Bump = bump;; + tex.FaceTextures[i].Bump = bump; } tex.DefaultTexture.Shiny = sval; tex.DefaultTexture.Bump = bump; @@ -1631,7 +1649,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f); tex.DefaultTexture.RGBA = texcolor; } - + part.UpdateTextureEntry(tex.GetBytes()); return; } @@ -1752,7 +1770,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api rgb.x = texcolor.R; rgb.y = texcolor.G; rgb.z = texcolor.B; - + return rgb; } else @@ -1784,12 +1802,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { UUID textureID = new UUID(); - textureID = InventoryKey(texture, (int)AssetType.Texture); - if (textureID == UUID.Zero) - { - if (!UUID.TryParse(texture, out textureID)) - return; - } + textureID = InventoryKey(texture, (int)AssetType.Texture); + if (textureID == UUID.Zero) + { + if (!UUID.TryParse(texture, out textureID)) + return; + } Primitive.TextureEntry tex = part.Shape.Textures; @@ -1986,7 +2004,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // IF YOU GET REGION CROSSINGS WORKING WITH THIS FUNCTION, REPLACE THE WORKAROUND. // // This workaround is to prevent silent failure of this function. - // According to the specification on the SL Wiki, providing a position outside of the + // According to the specification on the SL Wiki, providing a position outside of the if (pos.x < 0 || pos.x > Constants.RegionSize || pos.y < 0 || pos.y > Constants.RegionSize) { return 0; @@ -2195,7 +2213,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { return llGetRootRotation(); } - + m_host.AddScriptLPS(1); Quaternion q = m_host.GetWorldRotation(); return new LSL_Rotation(q.X, q.Y, q.Z, q.W); @@ -2882,7 +2900,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // we need to convert from a vector describing // the angles of rotation in radians into rotation value LSL_Rotation rot = llEuler2Rot(angle); - + // Per discussion with Melanie, for non-physical objects llLookAt appears to simply // set the rotation of the object, copy that behavior PhysicsActor pa = m_host.PhysActor; @@ -2958,7 +2976,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!UUID.TryParse(id, out objectID)) objectID = UUID.Zero; - + if (objectID == UUID.Zero && name == "") return; @@ -3142,19 +3160,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api msg.ParentEstateID = 0; //ParentEstateID; msg.Position = new Vector3(m_host.AbsolutePosition); msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid; - msg.binaryBucket + msg.binaryBucket = Util.StringToBytes256( - "{0}/{1}/{2}/{3}", - World.RegionInfo.RegionName, - (int)Math.Floor(m_host.AbsolutePosition.X), - (int)Math.Floor(m_host.AbsolutePosition.Y), + "{0}/{1}/{2}/{3}", + World.RegionInfo.RegionName, + (int)Math.Floor(m_host.AbsolutePosition.X), + (int)Math.Floor(m_host.AbsolutePosition.Y), (int)Math.Floor(m_host.AbsolutePosition.Z)); if (m_TransferModule != null) { m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); } - + ScriptSleep(2000); } @@ -3279,7 +3297,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llRotLookAt(LSL_Rotation target, double strength, double damping) { m_host.AddScriptLPS(1); - + // Per discussion with Melanie, for non-physical objects llLookAt appears to simply // set the rotation of the object, copy that behavior PhysicsActor pa = m_host.PhysActor; @@ -4353,7 +4371,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llCollisionSound(string impact_sound, double impact_volume) { m_host.AddScriptLPS(1); - + // TODO: Parameter check logic required. m_host.CollisionSound = KeyOrName(impact_sound, AssetType.Sound); m_host.CollisionSoundVolume = (float)impact_volume; @@ -5043,7 +5061,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // SL spits out an empty string for types other than key & string // At the time of patching, LSL_Key is currently LSL_String, // so the OR check may be a little redundant, but it's being done - // for completion and should LSL_Key ever be implemented + // for completion and should LSL_Key ever be implemented // as it's own struct else if (!(src.Data[index] is LSL_String || src.Data[index] is LSL_Key)) @@ -5179,8 +5197,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - return string.Join(", ", - (new List(src.Data)).ConvertAll(o => + return string.Join(", ", + (new List(src.Data)).ConvertAll(o => { return o.ToString(); }).ToArray()); @@ -6223,7 +6241,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api SetParticleSystem(m_host, rules); } - private void SetParticleSystem(SceneObjectPart part, LSL_List rules) + private void SetParticleSystem(SceneObjectPart part, LSL_List rules) { if (rules.Length == 0) { @@ -6460,7 +6478,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.OwnerID, m_host.Name, destID, (byte)InstantMessageDialog.TaskInventoryOffered, false, string.Format("'{0}'", category), -// We won't go so far as to add a SLURL, but this is the format used by LL as of 2012-10-06 +// We won't go so far as to add a SLURL, but this is the format used by LL as of 2012-10-06 // false, string.Format("'{0}' ( http://slurl.com/secondlife/{1}/{2}/{3}/{4} )", category, World.Name, (int)pos.X, (int)pos.Y, (int)pos.Z), folderID, false, pos, bucket, false); @@ -6575,12 +6593,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String llAvatarOnLinkSitTarget(int linknum) { m_host.AddScriptLPS(1); - if(linknum == ScriptBaseClass.LINK_SET || + if(linknum == ScriptBaseClass.LINK_SET || linknum == ScriptBaseClass.LINK_ALL_CHILDREN || linknum == ScriptBaseClass.LINK_ALL_OTHERS) return UUID.Zero.ToString(); - + List parts = GetLinkParts(linknum); - if (parts.Count == 0) return UUID.Zero.ToString(); + if (parts.Count == 0) return UUID.Zero.ToString(); return parts[0].SitTargetAvatar.ToString(); } @@ -6952,7 +6970,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api hollow = 0.70f; } } - // Otherwise, hollow is limited to 95%. + // Otherwise, hollow is limited to 95%. else { if (hollow > 0.95f) @@ -8133,16 +8151,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0)); // float revolutions - res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d); + res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d); // Slightly inaccurate, because an unsigned byte is being used to represent - // the entire range of floating-point values from 1.0 through 4.0 (which is how + // the entire range of floating-point values from 1.0 through 4.0 (which is how // SL does it). // - // Using these formulas to store and retrieve PathRevolutions, it is not - // possible to use all values between 1.00 and 4.00. For instance, you can't + // Using these formulas to store and retrieve PathRevolutions, it is not + // possible to use all values between 1.00 and 4.00. For instance, you can't // represent 1.10. You can represent 1.09 and 1.11, but not 1.10. So, if you // use llSetPrimitiveParams to set revolutions to 1.10 and then retreive them - // with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar + // with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar // behavior in the viewer as you cannot set 1.10. The viewer jumps to 1.11. // In SL, llSetPrimitveParams and llGetPrimitiveParams can set and get a value // such as 1.10. So, SL must store and retreive the actual user input rather @@ -10264,9 +10282,60 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api IHttpRequestModule httpScriptMod = m_ScriptEngine.World.RequestModuleInterface(); List param = new List(); - foreach (object o in parameters.Data) + bool ok; + Int32 flag; + + for (int i = 0; i < parameters.Data.Length; i += 2) { - param.Add(o.ToString()); + ok = Int32.TryParse(parameters.Data[i].ToString(), out flag); + if (!ok || flag < 0 || + flag > (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE) + { + throw new ScriptException("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) + throw new ScriptException("Missing name/value for custom header at parameter " + i.ToString()); + break; + } + + if (HttpStandardHeaders.Contains(parameters.Data[i].ToString(), StringComparer.OrdinalIgnoreCase)) + throw new ScriptException("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; @@ -10376,12 +10445,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide) { m_host.AddScriptLPS(1); - + ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y); if (lo == null) return 0; - + IPrimCounts pc = lo.PrimCounts; if (sim_wide != ScriptBaseClass.FALSE) @@ -10411,7 +10480,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api else if (category == ScriptBaseClass.PARCEL_COUNT_TEMP) return 0; // counts not implemented yet } - + return 0; } @@ -10754,7 +10823,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return ret; } } - + return new LSL_List(); } @@ -11381,7 +11450,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api else { ScenePresence sp = World.GetScenePresence(result.ConsumerID); - /// It it a boy? a girl? + /// It it a boy? a girl? if (sp != null) itemID = sp.UUID; } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 9bf1a64cf9..86ab03aedc 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -355,6 +355,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int HTTP_MIMETYPE = 1; public const int HTTP_BODY_MAXLENGTH = 2; public const int HTTP_VERIFY_CERT = 3; + public const int HTTP_VERBOSE_THROTTLE = 4; + public const int HTTP_CUSTOM_HEADER = 5; + public const int HTTP_PRAGMA_NO_CACHE = 6; public const int PRIM_MATERIAL = 2; public const int PRIM_PHYSICS = 3; @@ -635,7 +638,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int TOUCH_INVALID_FACE = -1; public static readonly vector TOUCH_INVALID_TEXCOORD = new vector(-1.0, -1.0, 0.0); public static readonly vector TOUCH_INVALID_VECTOR = ZERO_VECTOR; - + // constants for llGetPrimMediaParams/llSetPrimMediaParams public const int PRIM_MEDIA_ALT_IMAGE_ENABLE = 0; public const int PRIM_MEDIA_CONTROLS = 1; @@ -652,15 +655,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PRIM_MEDIA_WHITELIST = 12; public const int PRIM_MEDIA_PERMS_INTERACT = 13; public const int PRIM_MEDIA_PERMS_CONTROL = 14; - + public const int PRIM_MEDIA_CONTROLS_STANDARD = 0; public const int PRIM_MEDIA_CONTROLS_MINI = 1; - + public const int PRIM_MEDIA_PERM_NONE = 0; public const int PRIM_MEDIA_PERM_OWNER = 1; public const int PRIM_MEDIA_PERM_GROUP = 2; public const int PRIM_MEDIA_PERM_ANYONE = 4; - + // extra constants for llSetPrimMediaParams public static readonly LSLInteger LSL_STATUS_OK = new LSLInteger(0); public static readonly LSLInteger LSL_STATUS_MALFORMED_PARAMS = new LSLInteger(1000); @@ -677,7 +680,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const string TEXTURE_PLYWOOD = "89556747-24cb-43ed-920b-47caed15465f"; public const string TEXTURE_TRANSPARENT = "8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"; public const string TEXTURE_MEDIA = "8b5fec65-8d8d-9dc5-cda8-8fdf2716e361"; - + // Constants for osGetRegionStats public const int STATS_TIME_DILATION = 0; public const int STATS_SIM_FPS = 1; @@ -730,7 +733,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public static readonly LSLInteger RC_GET_ROOT_KEY = 2; public static readonly LSLInteger RC_GET_LINK_NUM = 4; - public static readonly LSLInteger RCERR_UNKNOWN = -1; + public static readonly LSLInteger RCERR_UNKNOWN = -1; public static readonly LSLInteger RCERR_SIM_PERF_LOW = -2; public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = 3; diff --git a/prebuild.xml b/prebuild.xml index 4c18aa8a97..7e28dee4e8 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2327,6 +2327,7 @@ ../../../../../../bin/ +