Receive POST body of an URLLoader

.NET Edition of the F-IN-BOX
fder
Posts: 12
Joined: Fri Jan 16, 2009 2:52 pm

Receive POST body of an URLLoader

Postby fder » Fri Jan 16, 2009 3:05 pm

Hi, is it possible to get the POST body of an URLLoader in c# when called from an swf?

AS3:

Code: Select all

var request:URLRequest = new URLRequest(url);
request.method = URLRequestMethod.POST;
request.contentType = "application/octet-stream";
request.data = "some data";

var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.load(request);

I know how to receive it in c#:

Code: Select all

flashCtl.AxCode.OnLoadExternalResourceByFullPath += new f_in_box__lib.AxCode.OnLoadExternalResourceByFullPathEventHandler(flashCtl_OnLoadExternalResourceByFullPath);
flashCtl.OnLoadExternalResourceByRelativePath += new f_in_box__lib.f_in_box__control.OnLoadExternalResourceByRelativePathEventHandler(flashCtl_OnLoadExternalResourceByRelativePath);

private void flashCtl_OnLoadExternalResourceByRelativePath(object sender, string path, Stream stream, ref bool handled)
{
    LoadExternalResource(path, stream, true, ref handled);
}

private void flashCtl_OnLoadExternalResourceByFullPath (object sender,string path,Stream stream,ref bool handled)
{
    LoadExternalResource (path,stream,true,ref handled);
}

private void LoadExternalResource (string path, Stream output, bool close, ref bool handled)
{
    // do something useful
}


But how can I get the "request.data" stream in c#? Or am I missing something obvious? :(

Softanics
Site Admin
Posts: 1402
Joined: Sat Sep 18, 2004 3:03 am
Location: Russia, St. Petersburg
Contact:

Postby Softanics » Sun Jan 18, 2009 3:28 pm

Thank you for your question.

Could you please check the event AxCode.OnSendData:

Code: Select all

f_in_box__control1.AxCode.OnSendData += new f_in_box__lib.AxCode.OnSendDataHandler(this.OnSendData);
...
public void OnSendData(object sender, byte[] buffer)
{
// buffer contains data to send
}


I hope this is what you need. If not -- we always are ready to add new feature to f-in-box.

Thank you!
Best regards, Artem A. Razin,
F-IN-BOX support
Ask your question here: http://www.f-in-box.com/support.html

fder
Posts: 12
Joined: Fri Jan 16, 2009 2:52 pm

Postby fder » Thu Jan 29, 2009 2:58 pm

Thank you! this is exactly what I needed. But now I have the following problem:

I get the "OnSendData" after I received the "OnLoadExternalResourceBy*Path". Is there a way to find out if the request is a GET or a POST? If it is a GET, I don't have to wait till I get the "OnSendData". If it is a POST, I do have to wait, till I get the "OnSendData". How can I see if it is POST or GET?

Softanics
Site Admin
Posts: 1402
Joined: Sat Sep 18, 2004 3:03 am
Location: Russia, St. Petersburg
Contact:

Postby Softanics » Fri Jan 30, 2009 8:22 am

Just to clarify: is OnSendData sending for GET requests too?

Thank you.
Best regards, Artem A. Razin,

F-IN-BOX support

Ask your question here: http://www.f-in-box.com/support.html

fder
Posts: 12
Joined: Fri Jan 16, 2009 2:52 pm

Postby fder » Fri Jan 30, 2009 9:28 am

No, it isn't. I only get OnSendData when using POST.

Softanics
Site Admin
Posts: 1402
Joined: Sat Sep 18, 2004 3:03 am
Location: Russia, St. Petersburg
Contact:

Postby Softanics » Mon Feb 02, 2009 7:58 am

The idea is the following:

Declare a few functions, a delegate and a structure:

Code: Select all

[StructLayout(LayoutKind.Sequential)]
   internal struct BINDINFO
{
   public Int32 cbSize;
   public Int32 szExtraInfo;
   public STGMEDIUM stgmedData;
   public Int32 grfBindInfoF;
   public Int32 dwBindVerb;
   public Int32 szCustomVerb;
   public Int32 cbstgmedData;
   public Int32 dwOptions;
   public Int32 dwOptionsFlags;
   public Int32 dwCodePage;
   public SECURITY_ATTRIBUTES securityAttributes;
   public Guid iid;
   public Int32 pUnk;
   public Int32 dwReserved;
}

internal delegate Int32 GetBindInfoHandler(UInt32 hFPC, ref Int32 grfBINDF, ref BINDINFO pbindinfo, Int32 lParam);
[DllImport("f_in_box.dll", EntryPoint = "FPC_AddGetBindInfoHandler", CallingConvention = CallingConvention.StdCall)]
internal static extern System.Int32 FPC_AddGetBindInfoHandler(UInt32 hFPC, GetBindInfoHandler pGetBindInfoHandler, Int32 lParam);
[DllImport("f_in_box.dll", EntryPoint = "FPC_RemoveGetBindInfoHandler", CallingConvention = CallingConvention.StdCall)]
internal static extern System.Int32 FPC_RemoveGetBindInfoHandler(UInt32 hFPC, Int32 dwCookie);


A handler:

Code: Select all

// Add your handler
FPC_AddGetBindInfoHandler(f_in_box__control1.AxCode.Handle, new GetBindInfoHandler(GetBindInfoHandler), 0);

private Int32 GetBindInfoHandler(UInt32 hFPC, ref Int32 grfBINDF, ref BINDINFO pbindinfo, Int32 lParam)
{
   // ...
}


GetBindInfoHandler will be called each time when new request is processes. It should be called for all requests, for GET and POST too.

BINDINFO (passed to a handler) is defined in MSDN:
msdn.microsoft.com/en-us/library/ms774966(VS.85).aspx

To check type (GET, POST, ...) test dwBindVerb field (BINDVERB):
msdn.microsoft.com/en-us/library/ms775134(VS.85).aspx

Thank you.
Best regards, Artem A. Razin,

F-IN-BOX support

Ask your question here: http://www.f-in-box.com/support.html

fder
Posts: 12
Joined: Fri Jan 16, 2009 2:52 pm

Postby fder » Mon Feb 02, 2009 9:23 am

Hello, thank you for your reply but I'm not really an InteropServices specialist. How do I translate the STGMEDIUM struct into C#? I had a look at the definition:

Code: Select all

typedef struct tagSTGMEDIUM
{
    DWORD tymed;
    [switch_type(DWORD), switch_is((DWORD) tymed)]
    union {
        [case(TYMED_GDI)]      HBITMAP        hBitmap;
        [case(TYMED_MFPICT)]   HMETAFILEPICT  hMetaFilePict;
        [case(TYMED_ENHMF)]    HENHMETAFILE   hEnhMetaFile;
        [case(TYMED_HGLOBAL)]  HGLOBAL        hGlobal;
        [case(TYMED_FILE)]     LPWSTR         lpszFileName;
        [case(TYMED_ISTREAM)]  IStream        *pstm;
        [case(TYMED_ISTORAGE)] IStorage       *pstg;
        [default] ;
    };
    [unique] IUnknown *pUnkForRelease;
}STGMEDIUM;
typedef STGMEDIUM *LPSTGMEDIUM;


but I'm stuck here. "SECURITY_ATTRIBUTES" should be no problem.

Softanics
Site Admin
Posts: 1402
Joined: Sat Sep 18, 2004 3:03 am
Location: Russia, St. Petersburg
Contact:

Postby Softanics » Mon Feb 02, 2009 9:26 am

fder wrote:Hello, thank you for your reply but I'm not really an InteropSerives specialist. How do I translate the STGMEDIUM struct into C#?


Oh, I'm sorry, I've forgotten about that. Here the definitions:

Code: Select all

      [StructLayout(LayoutKind.Sequential)]
         internal struct STGMEDIUM
      {
         public Int32 tymed;
         public Int32 hGlobal;
         public Int32 pUnkForRelease;
      }

      [StructLayout(LayoutKind.Sequential)]
         internal struct SECURITY_ATTRIBUTES
      {
         public Int32 nLength;
         public Int32 lpSecurityDescriptor;
         public Int32 bInheritHandle;
      }


Thank you.
Best regards, Artem A. Razin,

F-IN-BOX support

Ask your question here: http://www.f-in-box.com/support.html

fder
Posts: 12
Joined: Fri Jan 16, 2009 2:52 pm

Postby fder » Mon Feb 02, 2009 2:58 pm

Thank you! It works perfectly, but I have the same problem as "OnSendData": I get the "GetBindInfoHandler" after I get "OnLoadExternalResourceBy*Path"

In "OnLoadExternalResourceBy*Path", I need to fill the stream and set the handled boolean. The problem is that I can't fill the stream until I know if it is POST or GET. How can I solve this? Many thanks in advance!

Softanics
Site Admin
Posts: 1402
Joined: Sat Sep 18, 2004 3:03 am
Location: Russia, St. Petersburg
Contact:

Postby Softanics » Mon Feb 02, 2009 3:18 pm

fder wrote:The problem is that I can't fill the stream until I know if it is POST or GET. How can I solve this? Many thanks in advance!


Is GetBindInfoHandler called for POST requests only?

Thank you.
Best regards, Artem A. Razin,

F-IN-BOX support

Ask your question here: http://www.f-in-box.com/support.html

fder
Posts: 12
Joined: Fri Jan 16, 2009 2:52 pm

Postby fder » Tue Feb 03, 2009 9:19 am

No, like you said, in my case: it handle both GET and POST (I handle the processing of the stream in GetBindInfoHandler):
GetBindInfoHandler will be called each time when new request is processes. It should be called for all requests, for GET and POST too.

Softanics
Site Admin
Posts: 1402
Joined: Sat Sep 18, 2004 3:03 am
Location: Russia, St. Petersburg
Contact:

Postby Softanics » Tue Feb 03, 2009 10:14 am

What if to create a separate thread within the OnLoadExternalResourceBy*Path that waits a GetBindInfoHandler. The GetBindInfoHandler checks dwBindVerb field and send a message (set an event) to the thread?

Thank you.
Best regards, Artem A. Razin,

F-IN-BOX support

Ask your question here: http://www.f-in-box.com/support.html

fder
Posts: 12
Joined: Fri Jan 16, 2009 2:52 pm

Postby fder » Thu Feb 05, 2009 1:36 pm

Hello, I tried it the way you said, but unfortunately it doesn't work. The only way to solve the problem is if I get the request type (POST or GET) and the possible data (request.data) in "OnLoadExternalResourceBy*Path". (at least, that is what I think)

Softanics
Site Admin
Posts: 1402
Joined: Sat Sep 18, 2004 3:03 am
Location: Russia, St. Petersburg
Contact:

Postby Softanics » Thu Feb 05, 2009 3:33 pm

fder wrote:Hello, I tried it the way you said, but unfortunately it doesn't work. The only way to solve the problem is if I get the request type (POST or GET) and the possible data (request.data) in "OnLoadExternalResourceBy*Path". (at least, that is what I think)


OK... Have you tried this idea?

Thank you.
Best regards, Artem A. Razin,

F-IN-BOX support

Ask your question here: http://www.f-in-box.com/support.html

fder
Posts: 12
Joined: Fri Jan 16, 2009 2:52 pm

Postby fder » Mon Feb 09, 2009 12:23 pm

Euhm... I can't try this idea, because I receive only:
- string path
- Stream output
- bool close
- ref bool handled
in "OnLoadExternalResourceBy*Path". I should also recieve request type and post data in that method. To make everything clear, I made some dummy code:

steps:
- first: receive "OnLoadExternalResourceBy*Path", those methods both call: "LoadExternalResource". "LoadExternalResource" stores some info.
- second: receive "OnSendData". store the post data.
- third: receive "OnGetBindInfo": check if it is POST or GET and fill the info.Output stream, based on all the info (which doesn't work).

Code: Select all

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;

namespace Not.Working
{
    public enum RequestType { UNKNOWN = 0x00, GET = 0x01, POST = 0x02 };

    public partial class FlashControl : UserControl
    {
        internal delegate Int32 GetBindInfoHandler(UInt32 hFPC, ref Int32 grfBINDF, ref BINDINFO pbindinfo, Int32 lParam);
        [DllImport("f_in_box.dll", EntryPoint = "FPC_AddGetBindInfoHandler", CallingConvention = CallingConvention.StdCall)]
        internal static extern Int32 FPC_AddGetBindInfoHandler(UInt32 hFPC, GetBindInfoHandler pGetBindInfoHandler, Int32 lParam);
        [DllImport("f_in_box.dll", EntryPoint = "FPC_RemoveGetBindInfoHandler", CallingConvention = CallingConvention.StdCall)]
        internal static extern Int32 FPC_RemoveGetBindInfoHandler(UInt32 hFPC, Int32 dwCookie);
       
        public event ExternalInterfaceCallEventHandler OnExternalInterfaceCall;
        public event ExternalResourceLoaderEventHandler OnExternalResourceLoader;
       
        [StructLayout(LayoutKind.Sequential)]
        internal struct STGMEDIUM
        {
            public Int32 tymed;
            public Int32 hGlobal;
            public Int32 pUnkForRelease;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct SECURITY_ATTRIBUTES
        {
            public Int32 nLength;
            public Int32 lpSecurityDescriptor;
            public Int32 bInheritHandle;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct BINDINFO
        {
            public Int32 cbSize;
            public Int32 szExtraInfo;
            public STGMEDIUM stgmedData;
            public Int32 grfBindInfoF;
            public Int32 dwBindVerb;
            public Int32 szCustomVerb;
            public Int32 cbstgmedData;
            public Int32 dwOptions;
            public Int32 dwOptionsFlags;
            public Int32 dwCodePage;
            public SECURITY_ATTRIBUTES securityAttributes;
            public Guid iid;
            public Int32 pUnk;
            public Int32 dwReserved;
        }
       
        private f_in_box__lib.f_in_box__control flashCtl;
        private ServiceCallInfo info;

        public FlashControl(string context)
        {
            InitializeComponent();

            // loads flash player from resource
            Stream stream = new MemoryStream(Properties.Resources.FILE_FLASH);
            flashCtl = new f_in_box__lib.f_in_box__control(new f_in_box__lib.AxCode(stream));

            Controls.Add(flashCtl);

            // configure the control
            flashCtl.Context = context;
            flashCtl.StandardMenu = false;
            flashCtl.TransparentMode = true;
            flashCtl.FlashProperty_BackgroundColor = -1;
            flashCtl.FlashProperty_Base = "";
            flashCtl.FlashProperty_BGColor = "";
            flashCtl.FlashProperty_WMode = "Transparent";
            flashCtl.FlashProperty_ScaleMode = 3;
            flashCtl.FlashProperty_Quality = 1;
            flashCtl.FlashProperty_Menu = true;
            flashCtl.FlashProperty_AlignMode = 0;
            flashCtl.AxCode.SoundEnabled = true;
            flashCtl.AxCode.OnSendData += new f_in_box__lib.AxCode.OnSendDataHandler(AxCode_OnSendData);
            flashCtl.AxCode.OnLoadExternalResourceByFullPath += new f_in_box__lib.AxCode.OnLoadExternalResourceByFullPathEventHandler(flashCtl_OnLoadExternalResourceByFullPath);
            flashCtl.OnLoadExternalResourceByRelativePath += new f_in_box__lib.f_in_box__control.OnLoadExternalResourceByRelativePathEventHandler(flashCtl_OnLoadExternalResourceByRelativePath);
           
            // handler to check if it is post or get
            FPC_AddGetBindInfoHandler(flashCtl.AxCode.Handle, new GetBindInfoHandler(flashCtl_OnGetBindInfo), 0);
        }

        private Int32 flashCtl_OnGetBindInfo(UInt32 hFPC, ref Int32 grfBINDF, ref BINDINFO pbindinfo, Int32 lParam)
        {
            RequestType type = RequestType.UNKNOWN;

            // get
            if (pbindinfo.dwBindVerb == 0)
            {
                type = RequestType.GET;
            }
            // post
            else if (pbindinfo.dwBindVerb == 1)
            {
                type = RequestType.POST;
            }

            // finally I receive this event.
            // Now, I know everything I need to know to complete the request.
            // the problem is that it doesn't work.
            // If I fill the "info.Output" here, I don't receive a thing in flash.

            return 0;
        }

        private void AxCode_OnSendData(object sender, byte[] buffer)
        {
            info.Post = buffer;

            // At this moment I know the post data, but I still don't know if it is POST or GET,
            // So again, I store the post data into the "ServiceCallInfo" object
        }

        private void flashCtl_OnLoadExternalResourceByRelativePath(object sender, string path, Stream stream, ref bool handled)
        {
            LoadExternalResource(path, stream, ref handled, true);
        }

        private void flashCtl_OnLoadExternalResourceByFullPath(object sender, string path, Stream stream, ref bool handled)
        {
            LoadExternalResource(path, stream, ref handled, false);
        }

        private void LoadExternalResource(string path, Stream stream, ref bool handled, bool relative)
        {
            info = new ServiceCallInfo();
            info.Relative = relative;
            info.Handled = handled;
            info.Path = path;
            info.Output = stream;

            // I should handle the stream here, but at this moment, I don't know if it is POST or GET and what the possible post data is.
            // so: I store these params in a "ServiceCallInfo" object and wait till I receive a "OnSendData"
        }

        private class ServiceCallInfo
        {
            private byte[] post = null;
            private string path = null;
            private Stream output = null;
            private bool close = false;
            private bool handled = false;
            private bool relative = false;

            public byte[] Post
            {
                set { post = value; }
                get { return post; }
            }
            public string Path
            {
                set { path = value; }
                get { return path; }
            }
            public Stream Output
            {
                set { output = value; }
                get { return output; }
            }
            public bool Close
            {
                set { close = value; }
                get { return close; }
            }
            public bool Handled
            {
                set { handled = value; }
                get { return handled; }
            }
            public bool Relative
            {
                set { relative = value; }
                get { return relative; }
            }
        }
    }
}


If I fill the stream in "OnLoadExternalResourceBy*Path" as a test, it works:

Code: Select all

private void LoadExternalResource(string path, Stream stream, ref bool handled, bool relative)
{
      // fill the stream based on some hard-coded variables (e.g. RequestType = post and post data is a byte array).
}


But if I do it like in the dummy code, it doesn't work.

Additional question:
What is the meaning/functionality of setting the "handled" boolean in "OnLoadExternalResourceBy*Path"?


Return to “.NET Edition”

Who is online

Users browsing this forum: No registered users and 16 guests