Browse Source

Register HttpRequest to script.
Register Deserializer::Read() & Serializer::Write() to script. They operate on Array<uint8>.
Trim HttpRequest headers and do not add empty headers.

Lasse Öörni 12 years ago
parent
commit
6350f246e6

+ 53 - 0
Docs/ScriptAPI.dox

@@ -905,6 +905,7 @@ Properties:<br>
 Serializer
 
 Methods:<br>
+- uint Write(uint8[]@)
 - bool WriteInt(int)
 - bool WriteShort(int16)
 - bool WriteByte(int8)
@@ -937,6 +938,7 @@ Methods:<br>
 Deserializer
 
 Methods:<br>
+- uint8[]@ Read(uint)
 - int ReadInt()
 - int16 ReadShort()
 - int8 ReadByte()
@@ -980,6 +982,7 @@ Methods:<br>
 - void SendEvent(const String&, VariantMap& arg1 = VariantMap ( ))
 - bool Open(const String&, FileMode arg1 = FILE_READ)
 - void Close()
+- uint Write(uint8[]@)
 - bool WriteInt(int)
 - bool WriteShort(int16)
 - bool WriteByte(int8)
@@ -1007,6 +1010,7 @@ Methods:<br>
 - bool WriteVLE(uint)
 - bool WriteNetID(uint)
 - bool WriteLine(const String&)
+- uint8[]@ Read(uint)
 - int ReadInt()
 - int16 ReadShort()
 - int8 ReadByte()
@@ -1058,6 +1062,7 @@ Methods:<br>
 - void SetData(Deserializer@, uint)
 - void Clear()
 - void Resize(uint)
+- uint Write(uint8[]@)
 - bool WriteInt(int)
 - bool WriteShort(int16)
 - bool WriteByte(int8)
@@ -1085,6 +1090,7 @@ Methods:<br>
 - bool WriteVLE(uint)
 - bool WriteNetID(uint)
 - bool WriteLine(const String&)
+- uint8[]@ Read(uint)
 - int ReadInt()
 - int16 ReadShort()
 - int8 ReadByte()
@@ -5852,6 +5858,52 @@ Properties:<br>
 - VariantMap identity
 
 
+HttpRequest
+
+Methods:<br>
+- uint8[]@ Read(uint)
+- int ReadInt()
+- int16 ReadShort()
+- int8 ReadByte()
+- uint ReadUInt()
+- uint16 ReadUShort()
+- uint8 ReadUByte()
+- bool ReadBool()
+- float ReadFloat()
+- IntRect ReadIntRect()
+- IntVector2 ReadIntVector2()
+- Vector2 ReadVector2()
+- Vector3 ReadVector3()
+- Vector3 ReadPackedVector3(float)
+- Vector4 ReadVector4()
+- Quaternion ReadQuaternion()
+- Quaternion ReadPackedQuaternion()
+- Color ReadColor()
+- BoundingBox ReadBoundingBox()
+- String ReadString()
+- String ReadFileID()
+- StringHash ReadStringHash()
+- ShortStringHash ReadShortStringHash()
+- Variant ReadVariant()
+- VariantMap ReadVariantMap()
+- uint ReadVLE()
+- uint ReadNetID()
+- String ReadLine()
+- uint Seek(uint)
+
+Properties:<br>
+- int refs (readonly)
+- int weakRefs (readonly)
+- String name (readonly)
+- uint checksum (readonly)
+- uint position (readonly)
+- uint size (readonly)
+- bool eof (readonly)
+- String url (readonly)
+- String verb (readonly)
+- bool open (readonly)
+
+
 Network
 
 Methods:<br>
@@ -5868,6 +5920,7 @@ Methods:<br>
 - void UnregisterRemoteEvent(const String&) const
 - void UnregisterAllRemoteEvents()
 - bool CheckRemoteEvent(const String&) const
+- HttpRequest@ MakeHttpRequest(const String&, const String& arg1 = String ( ), String[]@ arg2 = null, const String& arg3 = String ( ))
 
 Properties:<br>
 - int refs (readonly)

+ 20 - 9
Source/Engine/Network/HttpRequest.cpp

@@ -23,6 +23,7 @@
 #include "Precompiled.h"
 #include "HttpRequest.h"
 #include "Log.h"
+#include "Profiler.h"
 #include "StringUtils.h"
 
 #include <civetweb.h>
@@ -35,23 +36,27 @@ namespace Urho3D
 static const unsigned ERROR_BUFFER_LEN = 256;
 
 HttpRequest::HttpRequest(const String& url, const String& verb, const Vector<String>& headers, const String& postData) :
-    url_(url),
+    url_(url.Trimmed()),
     verb_(!verb.Empty() ? verb : "GET"),
     connection_(0)
 {
+    // Size of response is unknown, so just set maximum value. The position will also be changed
+    // to maximum value once the request is done, signaling end for Deserializer::IsEof().
+    size_ = M_MAX_UNSIGNED;
+    
     String protocol = "http";
     String host;
     String path = "/";
     int port = 80;
     
-    unsigned protocolEnd = url.Find("://");
+    unsigned protocolEnd = url_.Find("://");
     if (protocolEnd != String::NPOS)
     {
-        protocol = url.Substring(0, protocolEnd);
-        host = url.Substring(protocolEnd + 3);
+        protocol = url_.Substring(0, protocolEnd);
+        host = url_.Substring(protocolEnd + 3);
     }
     else
-        host = url;
+        host = url_;
     
     unsigned pathStart = host.Find('/');
     if (pathStart != String::NPOS)
@@ -72,9 +77,14 @@ HttpRequest::HttpRequest(const String& url, const String& verb, const Vector<Str
     char errorBuffer[ERROR_BUFFER_LEN];
     memset(errorBuffer, 0, sizeof(errorBuffer));
     
-    String headerStr;
+    String headersStr;
     for (unsigned i = 0; i < headers.Size(); ++i)
-        headerStr += headers[i] + "\r\n";
+    {
+        // Trim and only add non-empty header strings
+        String header = headers[i].Trimmed();
+        if (header.Length())
+            headersStr += header + "\r\n";
+    }
     
     /// \todo SSL mode will not actually work unless Civetweb's SSL mode is initialized with an external SSL DLL
     if (postData.Empty())
@@ -83,7 +93,7 @@ HttpRequest::HttpRequest(const String& url, const String& verb, const Vector<Str
             "%s %s HTTP/1.0\r\n"
             "Host: %s\r\n"
             "%s"
-            "\r\n", verb_.CString(), path.CString(), host.CString(), headerStr.CString());
+            "\r\n", verb_.CString(), path.CString(), host.CString(), headersStr.CString());
     }
     else
     {
@@ -93,7 +103,7 @@ HttpRequest::HttpRequest(const String& url, const String& verb, const Vector<Str
             "%s"
             "Content-Length: %d\r\n"
             "\r\n"
-            "%s", verb_.CString(), path.CString(), host.CString(), headerStr.CString(), postData.Length(), postData.CString());
+            "%s", verb_.CString(), path.CString(), host.CString(), headersStr.CString(), postData.Length(), postData.CString());
     }
     
     if (!connection_)
@@ -124,6 +134,7 @@ void HttpRequest::Release()
     {
         mg_close_connection((mg_connection*)connection_);
         connection_ = 0;
+        position_ = M_MAX_UNSIGNED;
     }
 }
 

+ 6 - 2
Source/Engine/Network/HttpRequest.h

@@ -22,13 +22,14 @@
 
 #pragma once
 
+#include "Deserializer.h"
 #include "RefCounted.h"
 
 namespace Urho3D
 {
 
 /// HTTP request class.
-class HttpRequest : public RefCounted
+class HttpRequest : public RefCounted, public Deserializer
 {
 public:
     /// Construct with parameters.
@@ -37,7 +38,10 @@ public:
     ~HttpRequest();
 
     /// Read response data from the HTTP connection. Return bytes actually read or 0 on error or end of data.
-    unsigned Read(void* dest, unsigned size);
+    virtual unsigned Read(void* dest, unsigned size);
+    /// Set position from the beginning of the stream. Not supported
+    virtual unsigned Seek(unsigned position) { return position_; }
+    
     /// Return whether connection is still open.
     bool IsOpen() const { return connection_ != 0; }
     /// Return URL used in the request.

+ 2 - 0
Source/Engine/Network/Network.cpp

@@ -312,6 +312,8 @@ void Network::SetPackageCacheDir(const String& path)
 
 SharedPtr<HttpRequest> Network::MakeHttpRequest(const String& url, const String& verb, const Vector<String>& headers, const String& postData)
 {
+    PROFILE(MakeHttpRequest);
+    
     SharedPtr<HttpRequest> request(new HttpRequest(url, verb, headers, postData));
     const String& error = request->GetError();
     if (!error.Empty())

+ 35 - 6
Source/Engine/Script/APITemplates.h

@@ -91,10 +91,9 @@ template <class T> CScriptArray* VectorToArray(const PODVector<T>& vector, const
     {
         asIObjectType* type = GetScriptContext()->GetSubsystem<Script>()->GetObjectType(arrayName);
         CScriptArray* arr = new CScriptArray(vector.Size(), type);
-
-        for (unsigned i = 0; i < arr->GetSize(); ++i)
-            *(static_cast<T*>(arr->At(i))) = vector[i];
-
+        if (vector.Size())
+            memcpy(arr->At(0), &vector[0], vector.Size() * sizeof(T));
+        
         return arr;
     }
     else
@@ -191,6 +190,18 @@ template <class T> CScriptArray* VectorToHandleArray(const Vector<SharedPtr<T> >
         return 0;
 }
 
+/// Template function for array to Vector conversion.
+template <class T> Vector<T> ArrayToVector(CScriptArray* arr)
+{
+    Vector<T> dest(arr ? arr->GetSize() : 0);
+    if (arr)
+    {
+        for (unsigned i = 0; i < arr->GetSize(); ++i)
+            dest[i] = *static_cast<T*>(arr->At(i));
+    }
+    return dest;
+}
+
 /// Template function for registering implicit casts between base and subclass.
 template <class T, class U> void RegisterSubclass(asIScriptEngine* engine, const char* classNameT, const char* classNameU)
 {
@@ -204,9 +215,17 @@ template <class T, class U> void RegisterSubclass(asIScriptEngine* engine, const
     engine->RegisterObjectBehaviour(classNameU, asBEHAVE_IMPLICIT_REF_CAST, declReturnT.CString(), asFUNCTION((RefCast<U, T>)), asCALL_CDECL_OBJLAST);
 }
 
+/// Template function for writing to a serializer from an array.
+template <class T> unsigned SerializerWrite(CScriptArray* arr, T* ptr)
+{
+    unsigned bytesToWrite = arr->GetSize();
+    return bytesToWrite ? ptr->Write(arr->At(0), bytesToWrite) : 0;
+}
+
 /// Template function for registering a class derived from Serializer.
 template <class T> void RegisterSerializer(asIScriptEngine* engine, const char* className)
 {
+    engine->RegisterObjectMethod(className, "uint Write(Array<uint8>@+)", asFUNCTION(SerializerWrite<T>), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "bool WriteInt(int)", asMETHODPR(T, WriteInt, (int), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool WriteShort(int16)", asMETHODPR(T, WriteShort, (short), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool WriteByte(int8)", asMETHODPR(T, WriteByte, (signed char), bool), asCALL_THISCALL);
@@ -236,9 +255,19 @@ template <class T> void RegisterSerializer(asIScriptEngine* engine, const char*
     engine->RegisterObjectMethod(className, "bool WriteLine(const String&in)", asMETHODPR(T, WriteLine, (const String&), bool), asCALL_THISCALL);
 }
 
+/// Template function for reading from a serializer into an array.
+template <class T> CScriptArray* DeserializerRead(unsigned size, T* ptr)
+{
+    PODVector<unsigned char> vector(size);
+    unsigned bytesRead = size ? ptr->Read(&vector[0], size) : 0;
+    vector.Resize(bytesRead);
+    return VectorToArray(vector, "Array<uint8>");
+}
+
 /// Template function for registering a class derived from Deserializer.
 template <class T> void RegisterDeserializer(asIScriptEngine* engine, const char* className)
 {
+    engine->RegisterObjectMethod(className, "Array<uint8>@ Read(uint)", asFUNCTION(DeserializerRead<T>), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "int ReadInt()", asMETHODPR(T, ReadInt, (), int), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "int16 ReadShort()", asMETHODPR(T, ReadShort, (), short), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "int8 ReadByte()", asMETHODPR(T, ReadByte, (), signed char), asCALL_THISCALL);
@@ -285,7 +314,7 @@ template <class T> void RegisterRefCounted(asIScriptEngine* engine, const char*
     RegisterSubclass<RefCounted, T>(engine, "RefCounted", className);
 }
 
-template <class T> void ObjectSendEvent(const String& eventType, VariantMap& eventData,  T* ptr)
+template <class T> void ObjectSendEvent(const String& eventType, VariantMap& eventData, T* ptr)
 {
     if (ptr)
         ptr->SendEvent(StringHash(eventType), eventData);
@@ -461,7 +490,7 @@ static CScriptArray* NodeGetChildren(bool recursive, Node* ptr)
     return VectorToHandleArray<Node>(nodes, "Array<Node@>");
 }
 
-static CScriptArray* NodeGetChildrenWithComponent(String& typeName, bool recursive, Node* ptr)
+static CScriptArray* NodeGetChildrenWithComponent(const String& typeName, bool recursive, Node* ptr)
 {
     PODVector<Node*> nodes;
     ptr->GetChildrenWithComponent(nodes, typeName, recursive);

+ 1 - 1
Source/Engine/Script/Addons.cpp

@@ -91,7 +91,7 @@ static CScriptArray* ScriptArrayFactoryDefVal(asIObjectType *ot, asUINT length,
         return 0;
     }
 
-    return a;    
+    return a;
 }
 
 static CScriptArray* ScriptArrayFactory(asIObjectType *ot)

+ 0 - 8
Source/Engine/Script/CoreAPI.cpp

@@ -541,14 +541,6 @@ static CScriptArray* StringSplit(char separator, const String* str)
     return VectorToArray<String>(result, "Array<String>");
 }
 
-template <class T> Vector<T> ArrayToVector(CScriptArray* arr)
-{
-    Vector<T> dest(arr->GetSize());
-    for (unsigned i = 0; i < arr->GetSize(); ++i)
-        dest[i] = *static_cast<T*>(arr->At(i));
-    return dest;
-}
-
 static void StringJoin(CScriptArray* arr, const String& glue, String* str)
 {
     Vector<String> subStrings = ArrayToVector<String>(arr);

+ 22 - 0
Source/Engine/Script/NetworkAPI.cpp

@@ -23,6 +23,7 @@
 #include "Precompiled.h"
 #include "APITemplates.h"
 #include "Controls.h"
+#include "HttpRequest.h"
 #include "Network.h"
 #include "NetworkPriority.h"
 #include "Protocol.h"
@@ -118,6 +119,15 @@ static void RegisterConnection(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Node", "Connection@+ get_owner() const", asMETHOD(Node, GetOwner), asCALL_THISCALL);
 }
 
+static void RegisterHttpRequest(asIScriptEngine* engine)
+{
+    RegisterRefCounted<HttpRequest>(engine, "HttpRequest");
+    RegisterDeserializer<HttpRequest>(engine, "HttpRequest");
+    engine->RegisterObjectMethod("HttpRequest", "const String& get_url() const", asMETHOD(HttpRequest, GetURL), asCALL_THISCALL);
+    engine->RegisterObjectMethod("HttpRequest", "const String& get_verb() const", asMETHOD(HttpRequest, GetVerb), asCALL_THISCALL);
+    engine->RegisterObjectMethod("HttpRequest", "bool get_open() const", asMETHOD(HttpRequest, IsOpen), asCALL_THISCALL);
+}
+
 static Network* GetNetwork()
 {
     return GetScriptContext()->GetSubsystem<Network>();
@@ -159,6 +169,16 @@ static bool NetworkCheckRemoteEvent(const String& eventType, Network* ptr)
     return ptr->CheckRemoteEvent(eventType);
 }
 
+static HttpRequest* NetworkMakeHttpRequest(const String& url, const String& verb, CScriptArray* headers, const String& postData, Network* ptr)
+{
+    SharedPtr<HttpRequest> request = ptr->MakeHttpRequest(url, verb, ArrayToVector<String>(headers), postData);
+    // The shared pointer will go out of scope, so have to increment the reference count
+    // (here an auto handle can not be used)
+    if (request)
+        request->AddRef();
+    return request.Get();
+}
+
 void RegisterNetwork(asIScriptEngine* engine)
 {
     RegisterObject<Network>(engine, "Network");
@@ -174,6 +194,7 @@ void RegisterNetwork(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Network", "void UnregisterRemoteEvent(const String&in) const", asFUNCTION(NetworkUnregisterRemoteEvent), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Network", "void UnregisterAllRemoteEvents()", asMETHOD(Network, UnregisterAllRemoteEvents), asCALL_THISCALL);
     engine->RegisterObjectMethod("Network", "bool CheckRemoteEvent(const String&in) const", asFUNCTION(NetworkCheckRemoteEvent), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("Network", "HttpRequest@ MakeHttpRequest(const String&in, const String&in verb = String(), Array<String>@+ headers = null, const String&in postData = String())", asFUNCTION(NetworkMakeHttpRequest), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Network", "void set_updateFps(int)", asMETHOD(Network, SetUpdateFps), asCALL_THISCALL);
     engine->RegisterObjectMethod("Network", "int get_updateFps() const", asMETHOD(Network, GetUpdateFps), asCALL_THISCALL);
     engine->RegisterObjectMethod("Network", "void set_packageCacheDir(const String&in)", asMETHOD(Network, SetPackageCacheDir), asCALL_THISCALL);
@@ -189,6 +210,7 @@ void RegisterNetworkAPI(asIScriptEngine* engine)
     RegisterControls(engine);
     RegisterNetworkPriority(engine);
     RegisterConnection(engine);
+    RegisterHttpRequest(engine);
     RegisterNetwork(engine);
 }