views:

92

answers:

2

I'm trying to create/modify dotclear blogs.

For most of the options, i use XmlRpc API (DotClear.MetaWeblog). But didn't find any way to handle categories.

So I start to look at the Http packet and try to do "the same as the browser".

  1. Here si the method I use to "Http POST"

        protected HttpStatusCode HttpPost(Uri url_, string data_, bool allowAutoRedirect_)
        {
        HttpWebRequest Request;
        HttpWebResponse Response = null;
        Stream ResponseStream = null;
        Request = (System.Net.HttpWebRequest)HttpWebRequest.Create(url_);
        Request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)";
        Request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
        Request.AllowAutoRedirect = allowAutoRedirect_;
        // Add the network credentials to the request.
        Request.Credentials = new NetworkCredential(Username, Password);
    
    
    
    string authInfo = Username + ":" + Password;
    authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
    Request.Headers["Authorization"] = "Basic " + authInfo; 
    
    
    Request.Method = "POST";
    Request.CookieContainer = Cookies;
    if(ConnectionCookie!=null)
        Request.CookieContainer.Add(url_, ConnectionCookie);
    if (dcAdminCookie != null)
        Request.CookieContainer.Add(url_, dcAdminCookie);
    Request.PreAuthenticate = true;
    
    
    ASCIIEncoding encoding = new ASCIIEncoding();
    string postData = data_;
    byte[] data = encoding.GetBytes(postData); //Encoding.UTF8.GetBytes(data_);  //encoding.GetBytes(postData);
    Request.ContentLength = data.Length;
    Request.ContentType = "application/x-www-form-urlencoded";
    Stream newStream = Request.GetRequestStream();
    // Send the data.
    newStream.Write(data, 0, data.Length);
    newStream.Close();
    
    
    try
    {
        // get the response from the server.
        Response = (HttpWebResponse)Request.GetResponse();
        if (!allowAutoRedirect_)
        {
            foreach (Cookie c in Response.Cookies)
            {
                if (c.Name == "dcxd")
                    ConnectionCookie = c;
                if (c.Name == "dc_admin")
                    dcAdminCookie = c;
    
    
            }
    
    
            Cookies.Add(Response.Cookies);
        }
        // Get the response stream.
        ResponseStream = Response.GetResponseStream();
        // Pipes the stream to a higher level stream reader with the required encoding format. 
        StreamReader readStream = new StreamReader(ResponseStream, Encoding.UTF8);
        string result = readStream.ReadToEnd();
    
    
        if (Request.RequestUri == Response.ResponseUri)
        {
            _log.InfoFormat("{0} ==> {1}({2})", Request.RequestUri, Response.StatusCode, Response.StatusDescription);
        }
        else
        {
            _log.WarnFormat("RequestUri:{0}\r\nResponseUri:{1}\r\nstatus code:{2} Status descr:{3}", Request.RequestUri, Response.ResponseUri, Response.StatusCode, Response.StatusDescription);
        }
    }
    catch (WebException wex)
    {
        Response = wex.Response as HttpWebResponse;
    
    
        if (Response != null)
        {
            _log.ErrorFormat("{0} ==> {1}({2})", Request.RequestUri, Response.StatusCode, Response.StatusDescription);
        }
    
    
        Request.Abort();
    }
    finally
    {
        if (Response != null)
        { 
            // Releases the resources of the response.
            Response.Close();
        }
    
    
    }
    if(Response !=null)
        return Response.StatusCode;
    
    
    return HttpStatusCode.Ambiguous;
    
    }
  2. So the first thing to do is to Authenticate as admin. Here is the code:

    protected bool HttpAuthenticate() { Uri u = new Uri(this.Url); Uri url = new Uri(string.Format("{0}/admin/auth.php", u.GetLeftPart(UriPartial.Authority))); string data = string.Format("user_id={0}&user_pwd={1}&user_remember=1", Username, Password); var ret = HttpPost(url,data,false); return (ret == HttpStatusCode.OK || ret==HttpStatusCode.Found); }

3.Now that I'm authenticate, i need to get a xd_chek info (that i can find on the page so basically it's a GET on /admin/category.php + Regex("dotclear[.]nonce = '(.*)'"))

4.so I'm authenticate and have the xd_check info. The last thing to do seems to post the next category. But of course it does not work at all... here is the code:

string postData = string.Format("cat_title={0}&new_cat_parent={1}&xd_check={2}", category_, 0, xdCheck);
HttpPost(url, postData, true);

If anyone can help me and explain were is it wrong ?

thanks in advance.

A: 

What do you mean by "doesnt work"? What is happening from the server side? What HTTP response did you get back?

feroze
By doesn't work I mean that it seems that i'm not correctly authenticate when I do the post. On the last request, i get redirect to Auth page. Seem's like i loose the authentication when doing the post request.But when doing a get request, i'm authenticate because i can get the xd_check without being redirected to auth page.Maybee a problem with apache server
Pitming
Can you get a tracelog (http://ferozedaud.blogspot.com/2009/08/tracing-with-systemnet.html) and compare the differences between the GET and the POST request?I have read on the MSDN NCL forums that AutoRedirect does not seem to preserve cookies so forms post can fail in some instances. Maybe you are running into that?
feroze
Thx, obviously the cookies are the problems.
Pitming
A: 

Finaly I found the solution.

It seems that the cookies where lost between anthentication and use of the pages.

So I decide to not use de CookiesContainer of the framework but simply keep the cookies in a string and pass them at every request.

And it works great !

code exemple:

private string _cookieAsString = string.Empty;

    protected string CookieAsString
    {
        get { return _cookieAsString; }
        set
        {
            if (value != null)
            {
                if (!_cookieAsString.Contains(value))
                {
                    if (_cookieAsString.Length == 0)
                        _cookieAsString = value;
                    else
                        _cookieAsString += string.Format(";{0}", value);
                }
            }
        }
    }

And in the HttpWebRequest, I set it this way:

...
Request.Headers.Add(HttpRequestHeader.Cookie, CookieAsString);
...

And keep the cookies in the httpWebRequest like this:

...
CookieAsString = Response.Headers[HttpResponseHeader.SetCookie];
...
Pitming