Background Enabled Methods – Using Chilkat Asynchronously

Notice: The functionality described here is deprecated and replaced by a newer model for asynchronous method calls. The newer model was introduced in Chilkat v9.5.0.52, and is identified by methods having names ending in “Async” which return a task object.

The Chilkat HTTP component has a set of methods and properties that allow already-existing methods to be called asynchronously. For example, by setting the UseBgThread property equal to True, any background-enabled method, such as Download, will run in a background thread. Normally, when called synchronously, the method returns control to the caller only after the HTTP operation has completed. However, when UseBgThread = True, the method returns immediately and the HTTP operation is started in a background thread. (For a given HTTP object instance, only one background method may be ongoing at a time. It is possible to use multiple HTTP object instances, each of which might be processing a backgrounded method call.)

The set of background-enabling methods and properties are:

  • (property) UseBgThread – If True, then background-enabled methods will run in a background thread. Normally, a method will return after its work is completed. However, when UseBgThread is true, the method will return immediately and a background thread is started to carry out the method’s task.
  • (property) BgTaskRunning – If True then the object instance already has a backgrounded method running. Another backgrounded method cannot be started until the 1st completes. (Multiple simultaneous background methods may run by using multiple object instances.)
  • (property) BgTaskFinished – Becomes True when the background method completes. Your application would periodically check for this condition.
  • (property) BgTaskSuccess – Only meaningful (True/False) after a background method completes.
  • (property) BgLastErrorText – Last-error information is saved here and not in the LastErrorText property. If the background method fails, this will contain information about what transpired. (This property also contains information when the background method succeeds.)
  • (method) BgTaskAbort – Call this to force the currently running backgrounded method to abort.
  • (property) BgResultString – If the backgrounded method returns a string, the return value is found here.
  • (property) BgResultInt – If the backgrounded method returns an integer, the return value is found here.
  • (property) BgResultData – If the backgrounded method returns a byte array, the returned data is found here.
  • (method) BgResponseObject – If the backgrounded method returns an HttpResponse object, it may be retrieved by calling this method.


Example

An example of backgrounding the Download method may be found here.

Background Enabling other Chilkat Components
The HTTP component is the first Chilkat component to become background-enabled. The current development plan is to add the identical set of properties and methods to other Chilkat components to background-enable its functionality (such as for POP3, SMTP, IMAP, SSH, SFTP, Zip, MHT, etc.)

Asynchronous HTTP

Notice: The functionality described here is deprecated and replaced by a newer model for asynchronous method calls. The newer model was introduced in Chilkat v9.5.0.52, and is identified by methods having names ending in “Async” which return a task object.

The following example demonstrates the older, deprecated asynchronous HTTP functionality that allows for any HTTP method to be run asynchronously in a background thread:

ASP: HTTP in a Background Thread (Asynchronous HTTP)
SQL Server: HTTP in a Background Thread (Asynchronous HTTP)
C#: HTTP in a Background Thread (Asynchronous HTTP)
C++: HTTP in a Background Thread (Asynchronous HTTP)
MFC: HTTP in a Background Thread (Asynchronous HTTP)
C: HTTP in a Background Thread (Asynchronous HTTP)
Delphi: HTTP in a Background Thread (Asynchronous HTTP)
Visual FoxPro: HTTP in a Background Thread (Asynchronous HTTP)
Java: HTTP in a Background Thread (Asynchronous HTTP)
Perl: HTTP in a Background Thread (Asynchronous HTTP)
PHP: HTTP in a Background Thread (Asynchronous HTTP)
Python: HTTP in a Background Thread (Asynchronous HTTP)
Ruby: HTTP in a Background Thread (Asynchronous HTTP)
VB.NET: HTTP in a Background Thread (Asynchronous HTTP)
Visual Basic: HTTP in a Background Thread (Asynchronous HTTP)
VBScript: HTTP in a Background Thread (Asynchronous HTTP)

Debugging an HTTP Form Login

This is a summary of the steps I’m taking to debug the following problem:

	I am trying to login using Chilkat HTTP to this site: 
	http://www.mister-wong.com
	and after the login, there is a 302 redirect. After the redirect, the 
	session is lost.
	I believe it could be another cookie related issue.

1. Make sure I’m using the very latest version of the Chilkat HTTP component/library.

2. Set the SessionLogFilename property equal to the name of a log file the component will create. The exact HTTP requests and responses will be logged here. I’ll check them for cookies received and sent.

3. Call http.QuickGetStr(“http://www.mister-wong.com/”). Examine the session log and look for the Set-Cookie header in the response header. I see this:

	Set-Cookie: wongsess=d6f97305c1cacd528948f6ba6d41816c; expires=Sun, 10 Dec 2034 19:56:30 GMT; path=/

Look at the LastErrorText which contains information even when the method succeeded. Make sure it’s saving the cookie. It does because I see this:

    Saving cookies...
    Cookie:
      Domain: .mister-wong.com
      Path: /
      Expire: Sun, 10 Dec 2034 19:56:30 GMT
      CookieName: wongsess
      CookieValue: d6f97305c1cacd528948f6ba6d41816c
    SaveCookie:
      CookieDir: memory
      Domain: www.mister-wong.com
      HashKey: mister-wong_com.xml

4. OK, so far so good. Taking the next step — fetch the URL containing the login form: http://www.mister-wong.com/users/login/ The HTTP component *should* send the cookie previously received (if the cookie jar is “memory”, it must be the same instance of the HTTP object). The test code will now look like this:

            Chilkat.Http http = new Chilkat.Http();
            bool success = http.UnlockComponent("test");
            if (!success)
            {
                textBox1.Text = http.LastErrorText;
            }

            http.CookieDir = "memory";
            http.SaveCookies = true;
            http.SendCookies = true;

            http.SessionLogFilename = "httpSessionLog.txt";

            string html1 = http.QuickGetStr("http://www.mister-wong.com");
            textBox1.Text = http.LastErrorText;

            string html2 = http.QuickGetStr("http://www.mister-wong.com/users/login/");
            textBox1.Text += http.LastErrorText;
            textBox2.Text = html2; 

Looking at the LastErrorText for the 2nd QuickGetStr, I see this:

    AddingCookie: wongsess=a693f8b733aa146a235cd5edfa755da1

The cookie is re-sent as it should be.
Looking at the session log file, I see this for the 2nd GET request:

	---- Sending ----
	GET /users/login/ HTTP/1.1
	Accept: */*
	Accept-Encoding: gzip
	Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
	Accept-Language: en-us,en;q=0.5
	User-Agent: Chilkat/1.0.0 (+http://www.chilkatsoft.com/ChilkatHttpUA.asp)
	Cookie: wongsess=a693f8b733aa146a235cd5edfa755da1
	Host: www.mister-wong.com
	Connection: Keep-Alive

All looks OK.

5. Examine the HTML returned by the 2nd GET request. This should contain a login FORM. It does. Here it is:

<form id="UserLoginForm" method="post" action="/login">
<fieldset style="display:none;">
<input type="hidden" name="_method" value="POST" />
</fieldset>
<div class="input text required">
<label for="UserName">Username:</label>
<input name="data[User][name]" type="text" maxlength="40" value="" id="UserName" /></div>
<div class="input password">
<label for="UserPassword">Password:</label>
<input type="password" name="data[User][password]" value="" id="UserPassword" />
</div><div class="submit">
<input type="submit" value="Login" />
</div></form>

A POST must be sent to http://www.mister-wong.com/login, the values to be sent are: _method, data[User][name], data[User][password]. (The POST params are the “name” attributes of the “input” tags within the form. The type=”submit” input may be ignored — this is the submit button.

6. Add code to send the POST (actual username and password has been removed):

*** The customer’s mistake was the Path. The Path specified in the FORM is not “/users/login/”, it is “/login”. This is the Path that should be used for the POST:

            ....
            Chilkat.HttpRequest http_request = new Chilkat.HttpRequest();
            http_request.AddParam("data[User][name]", "***");
            http_request.AddParam("data[User][password]", "***");
            http_request.AddParam("_method", "POST");
            http_request.UsePost();
            http_request.Path = "/login";

            Chilkat.HttpResponse http_response = http.SynchronousRequest("www.mister-wong.com", 80, false, http_request);
            textBox1.Text += http.LastErrorText;
            textBox2.Text = html2; 

7. Examine the session log. I see this for the POST:

	---- Sending ----
	POST /login HTTP/1.1
	Host: www.mister-wong.com
	Content-Type: application/x-www-form-urlencoded
	Content-Length: 67
	Cookie: wongsess=2423f07ab5b543145f800717361ee8d9

	data[User][name]=***&data[User][password]=***&_method=POST

The actual username/password values have been replaced with “***”. I see the cookie was properly sent.

8. The response to the POST (in this case) is a 302 redirect:

	---- Received ----
	HTTP/1.1 302 Found
	Date: Thu, 10 Dec 2009 14:35:53 GMT
	Server: Apache
	P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
	Set-Cookie: WongCookie[Auth][User]=6d914d1612a372e523; expires=Fri, 10-Dec-2010 14:35:54 GMT; path=/
	Location: http://www.mister-wong.com/
	Content-Length: 0
	Content-Type: text/html; charset=UTF-8

9. A new cookie is set in the 302 response, and the Chilkat HTTP component redirects to the new URL. The proper action is to send an HTTP GET to the “Location” specified in the 302 response. The new cookie should be included in the GET. This is exactly what Chilkat HTTP does:

	GET / HTTP/1.1
	Accept: */*
	Accept-Encoding: gzip
	Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
	Accept-Language: en-us,en;q=0.5
	User-Agent: Chilkat/1.0.0 (+http://www.chilkatsoft.com/ChilkatHttpUA.asp)
	Cookie: wongsess=2423f07ab5b543145f800717361ee8d9; WongCookieAuthUser=6d914d1612a372e523
	Host: www.mister-wong.com
	Connection: Keep-Alive

10. The response is a “200 OK”:

	---- Received ----
	HTTP/1.1 200 OK
	Date: Thu, 10 Dec 2009 14:35:55 GMT
	Server: Apache
	P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
	Keep-Alive: timeout=5, max=97
	Connection: Keep-Alive
	Transfer-Encoding: chunked
	Content-Type: text/html; charset=UTF-8

All looks to be in order…

HTTP Session Logging

This example demonstrates how to use the new Chilkat HTTP SessionLogFilename property to log exact HTTP requests and responses to a file.  This can help in debugging…

ASP: HTTP Session Logging
SQL Server: HTTP Session Logging
C#: HTTP Session Logging
C++: HTTP Session Logging
MFC: HTTP Session Logging
C: HTTP Session Logging
Delphi: HTTP Session Logging
Visual FoxPro: HTTP Session Logging
Java: HTTP Session Logging
Perl: HTTP Session Logging
PHP: HTTP Session Logging
Python: HTTP Session Logging
Ruby: HTTP Session Logging
VB.NET: HTTP Session Logging
Visual Basic: HTTP Session Logging
VBScript: HTTP Session Logging

HTTP Cache-Control

Question:

Using the HTTP component I’m connecting and downloading an RSS feed via a Proxy server (fantastic!!).
Trouble is – the proxy is caching yesterday’s feed and I need to force the proxy to refresh it’s contents (that’s the proxy on my network – not the Chilkat local cache).

How can I tel the HTTP component to force the proxy to refresh?

I tried setting:

http.FreshnessAlgorithm = 1;
http.DefaultFreshPeriod = 1;
http.MaxFreshPeriod = 1;

to no avail.

Regards,

***
Licensed (and happy) Chilkat User….

Answer:

The HTTP header field definitions are defined here. Any header may be explicitly added to an HTTP request sent by Chilkat HTTP. For QuickGet* methods, call the SetRequestHeader method. The header you’ll probably want to add is “Cache-Control”, like this:

httpObject.SetRequestHeader("Cache-Control","no-cache");

SMTP over HTTP Proxy

ASP: SMTP using HTTP Proxy
SQL Server: SMTP using HTTP Proxy
C#: SMTP using HTTP Proxy
C++: SMTP using HTTP Proxy
MFC: SMTP using HTTP Proxy
C: SMTP using HTTP Proxy
Delphi: SMTP using HTTP Proxy
Visual FoxPro: SMTP using HTTP Proxy
Java: SMTP using HTTP Proxy
Perl: SMTP using HTTP Proxy
PHP: SMTP using HTTP Proxy
Python: SMTP using HTTP Proxy
Ruby: SMTP using HTTP Proxy
VB.NET: SMTP using HTTP Proxy
Visual Basic: SMTP using HTTP Proxy
VBScript: SMTP using HTTP Proxy

POP3 over HTTP Proxy

ASP: POP3 using HTTP Proxy
SQL Server: POP3 using HTTP Proxy
C#: POP3 using HTTP Proxy
C++: POP3 using HTTP Proxy
MFC: POP3 using HTTP Proxy
C: POP3 using HTTP Proxy
Delphi: POP3 using HTTP Proxy
Visual FoxPro: POP3 using HTTP Proxy
Java: POP3 using HTTP Proxy
Perl: POP3 using HTTP Proxy
PHP: POP3 using HTTP Proxy
Python: POP3 using HTTP Proxy
Ruby: POP3 using HTTP Proxy
VB.NET: POP3 using HTTP Proxy
Visual Basic: POP3 using HTTP Proxy
VBScript: POP3 using HTTP Proxy

HTTP Progress Monitoring in C++

This blog post shows how to monitor the progress of HTTP uploads and downloads in C++.  The first step is to create a C++ callback class that derives from the CkHttpProgress base class.  You’ll be overriding one or more of the callback methods.  For example:

class MyHttpProgress : public CkHttpProgress
    {
    public:
	MyHttpProgress(void) { }
	virtual ~MyHttpProgress(void) { }

	void PercentDone(int pctDone, bool *abort) 
	    { 
	    printf("PercentDone: %d percent\n",pctDone);

	    // To abort the HTTP operation, set the abort flag equal to true.
	    //if (pctDone > 10)
		//{
		//*abort = true;
		//}
	    }
	void AbortCheck(bool *abort) 
	    { 
	    // To abort the HTTP operation, set the abort flag equal to true.
            // Like this:
            // *abort = true;

            // Note: The AbortCheck event callback is called periodically according to the HeartbeatMs 
            // property setting.

	    printf("AbortCheck!\n");
	    }
	void HttpBeginReceive(void) { printf("HttpBeginReceive!\n"); }
	void HttpEndReceive(bool success) { printf("HttpEndReceive!\n"); }
	void HttpBeginSend(void) { printf("HttpBeginSend!\n"); }
	void HttpEndSend(bool success) { printf("HttpEndSend!\n"); }

    };

In your C++ application, create an instance of your MyHttpProgress class and tell the CkHttp object to use it by calling put_EventCallbackObject. Here’s an example:

void TestDownloadWithEventCallbacks(void)
    {
    MyHttpProgress eventObj;

    CkHttp http;
    bool success = http.UnlockComponent("Anything for 30-day trial");
    
    http.put_EventCallbackObject(&eventObj);

    success = http.Download("http://www.chilkatsoft.com/something/something.zip","something.zip");
    if (!success) 
        {
        printf("%s\n",http.lastErrorText());
        }
    else
        {
        printf("Finished.\n");
        }

    }

VB.NET HTTP Download with percent-done progress monitoring

Here is an example:

    Dim WithEvents http As Chilkat.Http

    Private Sub http_OnPercentDone(ByVal sender As Object, ByVal args As Chilkat.PercentDoneEventArgs) Handles http.OnPercentDone
        ProgressBar1.Value = args.PercentDone
    End Sub

    Private Sub HttpDownloadTest()

        http = New Chilkat.Http()

        Dim success As Boolean

        '  Any string unlocks the component for the 1st 30-days.
        success = http.UnlockComponent("Anything for 30-day trial")
        If (success <> True) Then
            MsgBox(http.LastErrorText)
            Exit Sub
        End If

        ' Enable event callbacks...
        http.EnableEvents = True

        '  Download the Python language install.
        '  Note: This URL may have changed since this example was created.
        success = http.Download("http://www.python.org/ftp/python/2.5/python-2.5.msi", "python-2.5.msi")
        If (success <> True) Then
            MsgBox(http.LastErrorText)
        Else
            MsgBox("Python Download Complete!")
        End If

        http = Nothing

    End Sub