views:

355

answers:

3

Below are 2 code snippets used to check if a folder exists in a SharePoint document library. The PROPFIND method seems to work, while the other method, using HEAD results in a 401.

Can someone please tell me why? Don't get distracted by the credentials, I've set it to the same in both examples, and it works fine....

Here is the code that works:

// Create the web request object
var oReq = (HttpWebRequest)WebRequest.Create(url);

// Set the needed properties
oReq.Method = "PROPFIND";
oReq.Credentials = this.wsLists.Credentials; // Use same credentials as wsLists. 
oReq.AllowAutoRedirect = true;
oReq.UserAgent = "Microsoft-WebDAV-MiniRedir/6.1.7600";

// Enumerate through top level only, increasing the depth will find children.
oReq.Headers["Depth"] = "0";
oReq.Headers["translate"] = "f";
var oRequest = new StreamWriter(oReq.GetRequestStream());
oRequest.WriteLine();
oRequest.Close();
var oResponse = new StreamReader(oReq.GetResponse().GetResponseStream());
string sResponse = oResponse.ReadToEnd();
oResponse.Close();

and here is the offending code:

private bool MossResourceExists(string url)
{
    var request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "HEAD";

    // Create a new CredentialCache object and fill it with the network
    // credentials required to access the server.
    var myCredentialCache = new CredentialCache();
    if (!string.IsNullOrEmpty(this.Domain ))
    {
        myCredentialCache.Add(new Uri(url),
       "NTLM",
       new NetworkCredential(this.Username , this.Password , this.Domain )
       );
    }
    else
    {
        myCredentialCache.Add(new Uri(url),
       "NTLM",
       new NetworkCredential(this.Username , this.Password )
       );
    }

    request.Credentials = myCredentialCache;

    try
    {
        request.GetResponse();
        return true;
    }
    catch (WebException ex)
    {
        var errorResponse = ex.Response as HttpWebResponse;

        if (errorResponse != null)
            if (errorResponse.StatusCode == HttpStatusCode.NotFound)
                return false;
            else
                throw new Exception("Error checking if URL exists:" + url + ";Status Code:" + errorResponse.StatusCode + ";Error Message:" + ex.Message ) ;
    }
    return true;
}
A: 

The request did not generate the 401. The 401 came from the server. You should look at the Windows Event Logs, IIS log, and SharePoint logs on the server, to see why the server returned a 401.

John Saunders
You're correct with the origin of the 401, but the server generated the 401 during the request in the 2nd example...
JL
Question updated, hope its clearer to understand now...
JL
I don't have the SharePoint API in front of me - does it say it supports HEAD for this request?
John Saunders
I have treated it as standard web dav. Another thing is for the base document library and 1 level down folder it works... only generates a 401 on 2 level down folders....
JL
A: 

I think the response is actually valid, and 401 is OK here. Look, 401 means "unauthorized". So, when you try to access a resource, SharePoint first checks your credentials to see if you are allowed to do it. If you don't have access, it will return 401, if you do, it will return 200+ contents of what you have asked for.

Now, what is the difference between the two:

  • when you are asking for resource you do not have access to
  • when you are asking for resource that does not exist

The basic principle in SharePoint is - if you don't have access to a thing, it DOES NOT EXIST for you and you SHOULDN'T know whether it exists or not.

If SharePoint allowed you to HEAD for a resource you do not have access to, you could try to look for http://sharepointsite/docs/JL_Gets_A_Salary_bonus.doc to see if you have a salary bonus or not.

This is why you get an "access denied" both on resources you don't have access to AND on resources that don't exist.

naivists
+1  A: 
Colin
Very good insight, thanks Colin.
JL