Search code examples
c#timezonewebdavsharpsvn

SVN_ERR_RA_DAV_REQUEST_FAILED when using SharpSVN.GetLog from program started with UTC-X time zone


I am using the SharpSvn NuGet package (version 1.14003.272) to access an SVN server over https.

Note: my PC is set to automatically adjust the time for summer time (daylight saving time), and I assume the server (running Windows Server) is doing the same. Therefore, when I say something uses the time zone CET (UTC+1) or ET (UTC-5), it will probably actually be CEST (UTC+2) or EDT (UTC-4) at the moment.

My computer (located in Germany) has a default time zone of CET. This is presumably the same as the server, which is also located in Germany.

Using that default setting, everything works fine.

But when I manually adjust the PC's time zone to Eastern Time (UTC-5) before I start the program, the SvnClient.GetLog function fails with an SvnRepositoryIOException.

This error comes only when the time zone was UTC-X at program launch, not when I had selected UTC or a UTC+X time zone.

Here are all relevant exception properties:

HResult: -2146233088
InnerException: null
Message: "Unexpected HTTP status 400 'Bad Request' on '/path/to/repository/!svn/me'"
Source: "SharpSvn"
StackTrace: <see below>
SvnErrorCategory: 35
SvnErrorCode: SVN_ERR_RA_DAV_REQUEST_FAILED (175002)

Here is the stack trace:

at SharpSvn.SvnClientArgs.HandleResult(SvnClientContext client, SvnException error, Object targets)
at SharpSvn.SvnClient.InternalLog(ICollection`1 targets, Uri logRoot, SvnRevision altPegRev, SvnLogArgs args, EventHandler`1 logHandler)
at SharpSvn.SvnClient.Log(ICollection`1 targets, SvnLogArgs args, EventHandler`1 logHandler)
at SharpSvn.SvnClient.GetLog(ICollection`1 targets, SvnLogArgs args, Collection`1& logItems)
at [stack of my methods starts here]

My App.xaml.cs looks like this:

public partial class App : PrismApplication
{
    protected override void Initialize()
    {  // X
        base.Initialize();

        // [...]
    }

    // [...]
}

I set a breakpoint on the line marked with // X; this is the first line of my code that the program ever runs, as far as I can tell. But the point of no return lies even earlier, somewhere in the framework's launch code:

  • The computer's time zone is UTC or UTC+X. I start the program, hit the breakpoint in line X, change the time zone to UTC-X, continue execution - GetLog works.
  • The time zone is UTC-X. I start, hit the breakpoint X, change to UTC or any UTC+X, continue - GetLog fails.

Here are some observations I made while trying to find the point of failure:

  • I got the same error when I was using SharpSvn.1.9-x64; I updated to SharpSVN in hopes of fixing the error that way, but unfortunately it didn't help.
  • UTC+14/3/2/1/0 and UTC itself all work, UTC-1 and UTC-5 do not.
  • The repository is over 2 years old, so it's not that UTC-X references a point in time where the repository didn't exist yet.
  • Using TortoiseSVN's "Show Log" from the right-click menu works at any time.
  • Performing "Checkout" or "Update" rather than "Show Log" works, regardless of any time zone shenanigans.
  • Using https or http for the requests does not make a difference.
  • I tried it with two different servers.

At this point, I don't even know where to look, since I don't know much about WebDAV and can't explain why the time zone setting only matters during app launch, and why it only matters for GetLog but not other commands.


Solution

  • I found the solution to avoid this error.

    In my own SvnGetLog method, the code was creating an "all revisions" SvnRevisionRange essentially like this:

    var range = new SvnRevisionRange(DateTime.MinValue, DateTime.MaxValue);

    However, DateTime.MinValue and DateTime.MaxValue are of DateTimeKind.Unspecified rather than DateTimeKind.Utc.

    There are several alternatives to create an SvnRevisionRange that works:

    • Replace DateTime.MinValue with new DateTime(DateTime.MinValue.Ticks, DateTimeKind.Utc) and do the same for DateTime.MaxValue.
    • Use 1970-01-01 00:00:00 Unspecified as from rather than the framework's DateTime.MinValue that's 0001-01-01 00:00:00 Unspecified.
    • Use new SvnRevisionRange(SvnRevision.Zero, SvnRevision.Head) (not an option for me, because the required API has DateTime parameters)

    I can't really provide a definitive explanation what happens internally, but I could imagine something like this:

    During application launch, the .NET framework stores the runtime environment's time zone and subsequently uses it to convert Unspecified timestamps into local time or UTC (basically an "educated guess").

    When I send a request starting at MinValue from a program that launched in an UTC or UTC+X environment, converting that timestamp to UTC will keep it at that date, or even shift it backwards into year 0. Maybe that triggers a special case that catches these values and assumes 'Start' without using the actual date value.

    When I'm launching at UTC-X however, MinValue would get converted to hour X of day 0001-01-01, which isn't 0 or negative, so the special case wouldn't trigger. This may lead to SVN actually trying to do some real calculations based on that date value, which causes the error because it's outside of UNIX time, or causes an underflow resulting in from > to or something like this.

    As I've said, I'm not at all certain this is how it works and what happens, but it would fit all the symptoms. Most importantly though, using DateTimeKind.Utc instead of DateTimeKind.Unspecified fixes the issue for me.